在从构造函数跳闸 UB 放置 new 后使用初始化变量?
Using initialized variable after placement new from the constructor tripping 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 实际上是 class 的一部分,它执行配置)
这个:
((R*)r)->foo = returns_some_valid_foo();
是未定义的行为。 r
上没有 R
类型的对象。句号。如果您翻转两条线以便首先创建 R
,那么您就可以了(模 r
未充分对齐)。
或者真的,只是:
R r;
r.foo = returns_some_valid_foo();
return r;
不管以下是否可以通过其他更安全的构造实现 - 我只是对以下是否会产生明确定义的输出感兴趣。
假设你有一个结构 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 实际上是 class 的一部分,它执行配置)
这个:
((R*)r)->foo = returns_some_valid_foo();
是未定义的行为。 r
上没有 R
类型的对象。句号。如果您翻转两条线以便首先创建 R
,那么您就可以了(模 r
未充分对齐)。
或者真的,只是:
R r;
r.foo = returns_some_valid_foo();
return r;