Disregarding whether the following can be achieved through other, more safe constructs - I'm simply interested in whether or not the following results in a well-defined output.
Assume you have a struct A:
struct A {
Foo* foo;
}
And a struct B inheriting from it:
struct B : A {
B() {
foo->some_function(); // UB
}
}
Sure enough if you were creating a B
instance the normal way you'd trip UB, however...
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?
Sheepishly assuming that C++ works like C somewhere under the hood, I'm guessing that this would be similar to having a struct instance in C, initializing it by hand, and then calling some method (in this case B's constructor) on the finished product.
Again, I'm not interested in whether you should do this or not, it's just a technical question.
EDIT:
If you wonder what this could be useful for, I could use it to pull out values into a plain struct from, say, a configuration file in a really terse manner. Yes it does use macros but call it a stub until C++ gets compile time reflection:
#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>();
(Using A and foo here to stay consistent with what I wrote above, make_A is actually part of a class that does config)
This:
((R*)r)->foo = returns_some_valid_foo();
is undefined behavior. There is no object of type R
at r
. Full stop. If you flip the two lines so that you create the R
first, then you're fine (modulo r
being insufficiently aligned).
Or really, just:
R r;
r.foo = returns_some_valid_foo();
return r;