Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 正在通过一个C++;对象转换为其自己的构造函数是否合法?_C++_Class_Constructor_Language Lawyer_Undefined Behavior - Fatal编程技术网

C++ 正在通过一个C++;对象转换为其自己的构造函数是否合法?

C++ 正在通过一个C++;对象转换为其自己的构造函数是否合法?,c++,class,constructor,language-lawyer,undefined-behavior,C++,Class,Constructor,Language Lawyer,Undefined Behavior,我意外地发现以下方法有效: #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

我意外地发现以下方法有效:

#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...
}
#包括
int main(int argc,字符**argv)
{
结构Foo{
Foo(Foo&bar){

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

其中包括:

如果是这样,UDT的自初始化的语义是什么? 比如说

 #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;
 }
决议是:

3.8[基本生活]第6段指出此处的引用是有效的。允许在类对象完全初始化之前获取其地址,并且允许将其作为参数传递给引用参数,只要引用可以直接绑定。除了未能将printfs中%p的指针强制转换为void*之外,这些PLE符合标准

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

类似地,在对象的生存期开始之前但在 对象将占用的存储已分配,或者 对象的生存期已结束,在 对象占用被重用或释放,任何引用 可以使用原始对象,但只能以有限的方式使用。对于对象 正在施工或破坏中,见12.7。否则,该值 指已分配的存储(3.7.4.2),并使用 不依赖于其值的glvalue是定义良好的 具有未定义的行为,如果:

  • 将左值到右值的转换(4.1)应用于该glvalue

  • glvalue用于访问的非静态数据成员或调用的非静态成员函数 反对,或

  • glvalue绑定到对虚拟基类(8.5.3)的引用,或

  • glvalue用作动态_转换(5.2.7)的操作数或typeid的操作数

我们没有对
foo
进行任何属于上述项目符号定义的未定义行为的操作

如果我们尝试使用叮当声,我们会看到一个不祥的警告():

警告:变量“foo”在其自身初始化中使用时未初始化[-Wuninitialized]

这是一个有效的警告,因为。但是,在这种情况下,您只是绑定一个引用,并在构造函数中获取变量的地址,这不会产生一个不确定的值,并且是有效的。另一方面:

调用未定义的行为


也似乎相关,但仍然是开放的。最初建议的语言与缺陷报告363一致。

在为要调用的对象分配内存的点调用构造函数。在该点上,该位置不存在任何对象(或者可能是具有普通析构函数的对象)。此外,
指针指向该内存,并且内存已正确对齐

由于它是已分配和对齐的内存,我们可以使用
Foo
类型的左值表达式(即
Foo&
)来引用它。我们可能还没有做的是左值到右值的转换。只有在输入构造函数体后才允许这样做

在这种情况下,代码只是试图在构造函数体内部打印
&bar
。在这里打印
bar.member
甚至是合法的。由于已输入构造函数体,因此存在
Foo
对象,可以读取其成员


这给我们留下了一个小细节,那就是名称查找。在
Foo-Foo(Foo)
中,第一个
Foo
在范围中引入名称,第二个
Foo
因此引用刚才声明的名称。这就是为什么
int x=x
无效,但
int x=sizeof(x)
是有效的。

@ShafikYaghmour为什么要删除你的答案?只需添加一个[basic.life]p6的引号作为限制。是的,这很好;它本质上与在构造函数中使用
这个
是一样的,有着所有的陷阱。这不是更像
size\t x=sizeof(x)
?在分配内存的位置调用对象的构造函数(来自未指定的源)。只要您只依赖于存储的属性,而不依赖于任何值的解释,事情就应该是安全的。@mAlters有一个微妙的问题,就是在将对象绑定到引用之前,即在构造函数调用之前,是否分配了存储。Shafik,根据您的建议,我暂时不接受您的回答,虽然对我来说已经够深了:)啊,好吧:)(不知何故,我没有想到这一点,认为这是理所当然的。)尽管如此,我认为标准中缺少了一个小细节。@dyp:确实没有精确指定,但必须在第一个基类构造函数开始执行之前对其进行排序。您无法确定之前的顺序。谢谢Shafik!在堆栈溢出问题上闲逛的人,以及站点提出正确问题的能力右眼的前方总是让我惊讶不已!对不起,我说的是原来的帖子/问题。无论如何,再想想,我可能误解了“构建”部分。我以为OP意味着我们将构造对象传递到该对象的构造函数中,而实际上我们将未初始化的对象传递到构造函数中。但在使用g++4.8编译
int x=x
时,我没有收到任何错误。无效语句应该会出错,对吗?@cbinder:应该,但不幸的是不会。
A::A(const A&) 0253FDD8 0253FDD8
A::~A() 0253FDD8
int x = x ;