将 C 对象传递到它自己的构造函数中合法吗?
像这样的代码的功能似乎令人困惑:
#include <iostream> struct Foo { Foo(Foo& bar) { std::cout << &bar << std::endl; } }; int main(int argc, char** argv) { Foo foo(foo); // I can't believe this works... std::cout << &foo << std::endl; // but it does... return 0; }
通过将未初始化对象的地址传递到其自己的构造函数中,我们似乎正在建立一个循环定义。问题出现了:标准是否允许在构造对象之前将对象传递给函数?或者这是否构成未定义行为?
合法,但并不罕见
将未初始化对象的地址传递到其自己的构造函数中并不是未定义行为。虽然 foo 未初始化,但我们以标准批准的方式使用它。
对象内存分配发生在完全初始化之前。因此,在此时间间隔内允许绑定对此类变量的引用并检索其地址。
此行为与缺陷报告 363 一致,该报告阐明在这种情况下创建的引用被视为有效。 C 14 标准的第 3.8 节 [basic.life] 进一步规定,在限制范围内使用引用已分配但未初始化对象的泛左值是允许的。
也就是说,我们不能应用左值到右值转换,访问非静态数据成员或调用非静态成员函数,绑定到虚拟基类引用,或使用dynamic_cast或typeid。
在我们的示例中,我们避免了这些禁止的操作,绑定引用并获取地址。
编译器警告
尽管行为合法,Clang 仍会发出警告:
warning: variable 'foo' is uninitialized when used within its own initialization [-Wuninitialized]
此警告是合理的,因为未初始化的值会生成不确定的值自动变量构成未定义的行为。尽管如此,我们的使用不会产生不确定的值,因此是合法的。
进一步的考虑因素
虽然通过将对象传递给其自己的构造函数来进行自初始化本质上并不是无论是有益的还是可取的,它都可以成为探索阶级行为的一种有趣的方法。然而,通过赋值进行自初始化,如 int x = x; ,确实构成了未定义的行为。
以上是将 C 对象传递到其自己的构造函数中是否合法?的详细内容。更多信息请关注PHP中文网其他相关文章!