gpt4 book ai didi

c++ - 将 C++ 对象传递给它自己的构造函数是否合法?

转载 作者:太空宇宙 更新时间:2023-11-04 12:37:35 25 4
gpt4 key购买 nike

我很惊讶无意中发现以下工作:

#include <iostream>            
int main(int argc, char** argv)
{
struct Foo {
Foo(Foo& bar) {
std::cout << &bar << std::endl;
}
};
Foo foo(foo); // I can't believe this works...
std::cout << &foo << std::endl; // but it does...
}

我将构造对象的地址传递给它自己的构造函数。这看起来像是源代码级别的循环定义。标准是否真的允许您在构造对象之前将对象传递给函数,或者这是未定义的行为?

我想这并不奇怪,因为所有类成员函数都已经有一个指向其类实例数据的指针作为隐式参数。并且数据成员的布局在编译时是固定的。

请注意,我不是在问这是否有用或一个好主意;我只是在修修补补以了解有关类(class)的更多信息。

最佳答案

这不是未定义的行为。尽管 foo 未初始化,但您正在以标准允许的方式使用它。在为对象分配空间之后但在完全初始化之前,您可以使用有限的方式使用它。允许绑定(bind)对该变量的引用并获取其地址。

defect report 363: Initialization of class from self 涵盖了这一点其中说:

And if so, what is the semantics of the self-initialization of UDT? For example

 #include <stdio.h>

struct A {
A() { printf("A::A() %p\n", this); }
A(const A& a) { printf("A::A(const A&) %p %p\n", this, &a); }
~A() { printf("A::~A() %p\n", this); }
};

int main()
{
A a=a;
}

can be compiled and prints:

A::A(const A&) 0253FDD8 0253FDD8
A::~A() 0253FDD8

决议是:

3.8 [basic.life] paragraph 6 indicates that the references here are valid. It's permitted to take the address of a class object before it is fully initialized, and it's permitted to pass it as an argument to a reference parameter as long as the reference can bind directly. Except for the failure to cast the pointers to void * for the %p in the printfs, these examples are standard-conforming.

C++14 标准草案中 3.8 [basic.life] 部分的完整引用如下:

Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage (3.7.4.2), and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if:

  • an lvalue-to-rvalue conversion (4.1) is applied to such a glvalue,

  • the glvalue is used to access a non-static data member or call a non-static member function of the object, or

  • the glvalue is bound to a reference to a virtual base class (8.5.3), or

  • the glvalue is used as the operand of a dynamic_cast (5.2.7) or as the operand of typeid.

我们不会对 foo 做任何属于上述项目符号定义的未定义行为的事情。

如果我们用 Clang 尝试这个,我们会看到一个不祥的警告 ( see it live ):

warning: variable 'foo' is uninitialized when used within its own initialization [-Wuninitialized]

producing an indeterminate value from an uninitialized automatic variable is undefined behavior 以来,这是一个有效的警告.但是,在这种情况下,您只是绑定(bind)一个引用并在构造函数中获取变量的地址,这不会产生不确定的值并且是有效的。另一方面,following self-initialization example from the draft C++11 standard :

int x = x ;

确实会调用未定义的行为。

Active issue 453: References may only bind to “valid” objects 似乎也相关,但仍然开放。最初提议的语言与缺陷报告 363 一致。

关于c++ - 将 C++ 对象传递给它自己的构造函数是否合法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55696090/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com