传递一个C ++对象到自己的构造函数合法吗?
我惊讶地意外地发现以下的作品:
#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... }
我将构造对象的地址传递给它自己的构造函数。 这看起来像来源层面的循环定义。 标准是否真的允许你在对象构造之前将一个对象传入一个函数,或者这个未定义的行为?
我想这并不奇怪,因为所有的类成员函数都有一个指向其类实例的数据的指针,作为一个隐式参数。 数据成员的布局在编译时是固定的。
请注意,我不是问这是否有用或好主意, 我只是在学习更多的课程。
这不是未定义的行为,尽pipefoo
是未初始化的,您正在使用标准允许的方式。 在为对象分配空间之后,在完全初始化之前,允许以有限的方式使用空间。 绑定对该variables的引用并获取其地址是允许的。
这是由缺陷报告363:从自我类的初始化说:
如果是这样的话,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; }
可以编译打印:
A::A(const A&) 0253FDD8 0253FDD8 A::~A() 0253FDD8
决议是:
3.8 [basic.life]第6段表示这里的引用是有效的。 允许在完全初始化之前获取类对象的地址,只要引用可以直接绑定,就可以将其作为parameter passing给引用参数。 除了在printf中未能将指针转换为void *作为%p,这些示例是标准符合的。
C ++ 14标准草案第3.8
节[basic.life]的完整引用如下:
类似地,在对象的生命周期开始之前,但是在对象将要占用的存储之后,或者在对象的生命周期结束之后,在重新使用或释放该对象占用的存储之前,任何引用原始对象可以被使用,但是仅以有限的方式使用。 正在施工或破坏的物体见12.7。 否则,这样的glvalue是指分配的存储(3.7.4.2),并且使用不依赖于它的值的glvalue的属性是明确的。 该程序具有未定义的行为,如果:
一个左值到右值的转换(4.1)应用于这样一个glvalue,
glvalue用于访问非静态数据成员或调用对象的非静态成员函数
glvalue绑定到对虚拟基类(8.5.3)的引用,或者
glvalue用作dynamic_cast(5.2.7)的操作数或者作为typeid的操作数。
我们没有对foo
进行任何处理,这些foo
属于上面定义的未定义的行为。
如果我们用叮当试试这个,我们会看到一个不祥的警告( 见它现场 ):
警告:variables'foo'在初始化时被初始化[-Winitialized]
这是一个有效的警告,因为从未初始化的自动variables产生和不确定的值是未定义的行为,但在这种情况下,你只是绑定一个引用,并取得构造函数中的variables的地址不产生不确定的值,是有效的。 另一方面来自C ++ 11标准草案的以下自我初始化示例 :
int x = x ;
会调用未定义的行为。
主动问题453:引用可能只绑定到“有效”的对象也似乎相关,但仍然是开放的。 最初提出的语言与缺陷报告363一致。
构造函数在内存分配给待处理对象的地方被调用。 此时,在该位置不存在对象(或者可能是具有微不足道的析构函数的对象)。 而且, this
指针指的是内存和内存正确alignment。
由于分配和alignment的内存,我们可以使用Foo
types的左值expression式(即Foo&
)来引用它。 我们可能还没有做的是左值到右值的转换。 只有在构造函数体被input后才允许。
在这种情况下,代码只是试图在构造函数体内打印&bar
。 在这里打印bar.member
甚至是合法的。 由于构造函数体已经被input,所以Foo
对象存在并且其成员可以被读取。
这给我们留下了一个小细节,这就是名字查询。 在Foo foo(foo)
,第一个foo
在范围中引入了名称,第二个foo
因此返回到刚刚声明的名称。 这就是为什么int x = x
是无效的,但是int x = sizeof(x)
是有效的。