Используя инициализированную переменную после размещения нового из конструктора, отключающего UB?
Независимо от того, может ли быть достигнуто следующее с помощью других, более безопасных конструкций - меня просто интересует, приводят ли следующие результаты к четко определенному результату.
Предположим, у вас есть структура A:
struct A {
Foo* foo;
}
И структура B наследуется от него:
struct B : A {
B() {
foo->some_function(); // UB
}
}
Конечно же, если вы создавали B
Экземпляр нормальный способ, как вы бы отключить UB, однако...
template<typename R>
R make_A() { // This acts like a constructor for As
static_assert(std::is_base_of<A, R>::value, "R must derive from A");
char r[sizeof(R)];
((R*)r)->foo = returns_some_valid_foo();
new (r) R;
return *((R*)r);
}
B b1; // Blows up (Could you somehow prevent this from compiling without changing B?)
B b2 = make_A<B>(); // Works fine?
Застенчиво предполагая, что C++ работает как C где-то под капотом, я предполагаю, что это было бы похоже на наличие экземпляра структуры в C, инициализацию его вручную, а затем вызов некоторого метода (в данном случае конструктора B) для готового продукта.,
Опять же, меня не интересует, стоит ли вам это делать или нет, это просто технический вопрос.
РЕДАКТИРОВАТЬ:
Если вам интересно, для чего это может быть полезно, я мог бы использовать его для извлечения значений в простую структуру, скажем, из файла конфигурации, действительно кратким образом. Да, он использует макросы, но называет его заглушкой, пока C++ не получит отражение во время компиляции:
#define config_key($x, $def) $x = foo->get<decltype($x)>(#$x, ($def))
struct Record : A {
int config_key(a, 3); // Second parameter is default value
string config_key(b, "something");
}
auto record = make_A<Record>();
(Используя A и foo здесь, чтобы соответствовать тому, что я написал выше, make_A на самом деле является частью класса, который выполняет конфигурацию)
1 ответ
Это:
((R*)r)->foo = returns_some_valid_foo();
является неопределенным поведением. Там нет объекта типа R
в r
, Полная остановка. Если вы переверните две строки, чтобы создать R
во-первых, тогда ты в порядке (по модулю r
недостаточно выровнен).
Или действительно, просто:
R r;
r.foo = returns_some_valid_foo();
return r;