在T的构造函数中用* this = T()“初始化”T类型的对象是否安全?

时间:2011-08-16 23:42:40

标签: c++

在这种情况下,构造函数Year()是否安全?

struct Year {
   int year;
   Year(int y) : year(y) {}
   Year() { *this = Year(1970); } // *this = this->operator=(Year(1970));
};

Year y;

我想是的,因为一旦执行流程到达构造函数体,就已经用int()初始化了year。还有其他需要考虑的问题吗?

不要考虑其他相同技巧可能导致麻烦的情况。

3 个答案:

答案 0 :(得分:5)

当然,this will work,并且有效。


解释

所有数据成员和基础都已在您的ctor-body运行时构建,并且:

  

[n3290: 12.7/4] 会员功能,包括虚拟功能   (10.3),可以在施工或销毁期间调用(12.6.2)。 [..]

不要混淆:

  

[n3290: 12.7/1]对于具有非平凡构造函数的对象,引用任何   构造函数之前的对象的非静态成员或基类   以未定义的行为开始执行结果

(注意:“在构造函数开始之前”;此子句不适用于此处。)

12.8 "Copying and moving class objects"中没有任何内容禁止在施工期间进行分配。


买者

请注意,意味着该对象已开始其“生命周期”:

  

[n3290: 3.8/1]:类型为T的对象的生命周期始于:

     
      
  • 获得具有T类型的正确对齐和大小的存储,并且
  •   
  • 如果对象具有非平凡的初始化,则其初始化完成。
  •   

非委派代理人“初始化”的最后一步:

  

[n3290: 12.6.2/10]: [..]最后,执行构造函数体的复合语句。

总而言之,这意味着对象的“生命周期”在其最派生的构造函数体已完成执行之前不会开始。

特别是,在对象开始生命之前将指针传递给对象并不是很有用,因为通过该指针执行几乎任何操作都会调用未定义的行为:

  

[n3290: 3.5/8]:在对象的生命周期开始之前,但是   在已经分配了对象占用的存储之后   或者,在对象的生命周期结束之后和存储之前   对象占用的是重用或释放的,任何指针   指对象所在或存在的存储位置   可以使用但仅限于有限的方式。 [..]

然而:

  

[n3290: 3.8/3]: [..] [注意:[..]另外,一个对象的行为   正在建设和破坏可能不一样   生命周期已开始但未结束的对象的行为。 12.6.2   和12.7描述了施工过程中物体的行为   破坏阶段。 - 后注]

而且,正如我们已经探讨的那样,12.7请告诉我们,在此阶段的构建过程中,可能会访问


建议

但是你的方法很难遵循;在确定它是有效的之前,我还必须查看上面的段落,所以它显然不是完全直观的。

幸运的是,C ++ 0x引入了构造函数委派,因此您可以编写:

struct Year {
   Year()      : Year(1970) {}
   Year(int y) : year(y)    {}

   int year;
};

(唉,GCC 4.5.1不支持这一点,所以I cannot demonstrate it to you on ideone.com。事实上,for GCC as a whole there's only a "partial patch" at time of writing。)

答案 1 :(得分:2)

你正在做什么,但是如果你以某种方式递归地调用构造函数那会导致问题,那么什么是行不通的。但是,由于构造函数是在构造了对象的所有非静态数据成员之后调用的,并且this指针指向可以复制到的有效内存,所以你所做的就好了 - 它是不是标准做法,但没关系。

答案 2 :(得分:0)

这个答案可能是错的;请参阅Tomalak的回答和评论。我会因为历史原因离开它,但你可能在构造函数中调用成员函数。

绝对不是。如果您有任何T*,请说p,那么只有在p->指向某个对象时,您才可以通过p调用成员函数。但是一个对象只有在构造函数完成时才会开始。因此,当您处于构造函数的中间时,this不会指向对象!因此,您肯定不会在此非对象上调用任何成员函数,例如赋值运算符。

[Curiosum:在某些情况下, 是合法的delete this;,你只需要确保析构函数不以任何方式引用this。在构造函数中将this传递给其他位置也是可以的,只要它不是 dereferenced ,就像你可以传递任何垃圾指针一样,只要你不这样做使用它。]