什么时候可以安全地打电话给这个>在构造函数和析构函数中

时间:2015-05-15 11:42:35

标签: c++ c++11 constructor destructor

到目前为止,我还未能找到确凿的答案。何时从对象内调用this->是安全的。特别是从构造函数和析构函数内部。

而且,在使用公共继承时。使用向上和向下转换此调用的结果是否安全?

例如:

class foo
{
   foo():
   a(),
   b(this->a)//case 1
   {
       this-> a = 5; //case 2
   }

   int a;
   int b;
};

class bar: public baz
{
   bar():
   baz(this)//case 3 - assuming baz has a valid constructor
   {


   }

}

最后是最不可能的一个

foo()
   {
      if(static_cast<bar*>(this));//case 4
   }

上述哪些案件合法?

注意:我知道上面的很多做法都是不可取的。

2 个答案:

答案 0 :(得分:34)

在任何非静态成员函数中,this指向调用该函数的对象。只要这是一个有效的对象,它就是安全的。

在构造函数或析构函数的主体内,有一个当前正在构造的类的有效对象。但是,如果这是某个派生类的基础子对象,则此时只有基础子对象有效;因此,向下转换并尝试访问派生类的成员通常是不安全的。出于同样的原因,你需要小心地在这里调用虚函数,因为它们是根据正在创建或销毁的类调度的,而不是最终的覆盖。

在构造函数的初始化列表中,您只需要小心访问已初始化的成员;也就是说,成员在当前正在初始化之前声明。

向上扩展到基类总是安全的,因为基本子对象总是先被初始化。

对于您刚刚添加到问题的具体示例:

  • 案例1很好(如果是脆弱的),因为a已在此时初始化。使用a的值初始化b将是未定义的,因为在b之后初始化a
  • 案例2没问题:所有成员都已在此时初始化。
  • 案例3将无法编译,因为没有合适的foo构造函数。如果有,那么它将取决于构造函数对它做了什么 - 无论它是否在初始化之前尝试访问成员。
  • 如果您添加了缺少的),则情况4将是格式良好的,但如果您尝试使用指针访问该对象则会很危险。 this尚未指向有效的bar对象(仅foo部分已初始化),因此访问bar的成员可能会给出未定义的行为。只需检查指针是否为空即可,并且总是会给true(无论你是否应用无意义的强制转换)。

答案 1 :(得分:19)

在C ++ super-faq上有一个很好的条目:

https://isocpp.org/wiki/faq/ctors#using-this-in-ctors

  

有些人认为你不应该在构造函数中使用this指针   因为物体尚未完全形成。但是你可以使用它   在构造函数中(在{body}中,甚至在初始化列表中)   如果你小心的话。

     

以下是始终有效的东西:构造函数的{body}(或者   从构造函数调用的函数)可以可靠地访问数据   在基类中声明的成员和/或在中声明的数据成员   构造函数自己的类。这是因为所有这些数据成员   保证在时间之前完全建造   构造函数的{body}开始执行。

     

这是永远不会有用的东西:构造函数的{body}(或者   从构造函数调用的函数)无法归结为派生函数   class通过调用在。中重写的虚拟成员函数   派生类。如果你的目标是获得被覆盖的功能   派生类,你不会得到你想要的。请注意,你不会   获取派生类中的覆盖,与您调用的方式无关   虚拟成员函数:显式使用this指针(例如,   this-&gt; method()),隐式使用this指针(例如,method()),   甚至调用一些调用虚拟成员的其他函数   对你的这个对象起作用。底线是这样的:即使是   调用者正在构造一个派生类的对象   基类的构造函数,您的对象尚未派生   类。你被警告了。

     

以下是有时可行的方法:如果您传递任何数据   您必须在此对象中的成员到另一个数据成员的初始化程序   确保已初始化其他数据成员。该   好消息是你可以确定其他数据成员是否有   (或尚未)使用一些简单的语言进行初始化   与您正在使用的特定编译器无关的规则。   坏消息是你必须知道那些语言规则(例如,基础   首先初始化class子对象(如果有的话,查找顺序)   多个和/或虚拟继承!),然后定义数据成员   该类按它们出现在的顺序初始化   班级宣言)。如果您不了解这些规则,那么请不要通过任何规则   来自此对象的数据成员(无论您是否   显式地使用this关键字)到任何其他数据成员   初始化!如果您确实了解规则,请小心。