繁体   English   中英

C ++中构造函数的初始化顺序

[英]Initialization order with constructors in C++

通过使用以下类在C ++中实例化对象,我会得到分段错误或中止,具体取决于声明成员变量的顺序。 E. g。 在mAnotherCountVar之后输入mMemberVar和mAnotherMemberVar会导致段错误。 从这个列表中我从成员变量中删除了一个std :: ofstream,这导致了与其位置无关的分段错误。

我认为订单不是直接问题,但您认为原因是什么? 这个类是一个巨大的项目的一部分,但是这个类中的这个地方是第一次出现错误的地方。

class COneClass : public IInterface
{
public:

  COneClass();

  virtual ~COneClass();

  static const unsigned int sStaticVar;
  static const unsigned int sAnotherStaticVar;


private:
  COneClass();
  COneClass(const COneClass& );
  COneClass& operator=(const COneClass& );

  int mMemberVar;
  int mAnotherMemberVar;
  bool mIsActive;
  bool mBoolMemberVar;
  bool mAnotherBoolMemberVar;
  unsigned int mCountVar;
  unsigned int mAnotherCountVar;
};

COneClass::COneClass() :
  mMemberVar(0),
  mAnotherMemberVar(0),
  mIsActive(false), 
  mBoolMemberVar(false),
  mAnotherBoolMemberVar(false),
  mCountVar(sStaticVar),
  mAnotherCountVar(sAnotherStaticVar)
{
}

类成员由声明它们的顺序初始化。 init列表中的顺序无关紧要。 在你的情况下,它是这个顺序:mMemberVar - > mAnotherMemberVar - > mIsActive - > mBoolMemberVar - > mAnotherBoolMemberVar - > mCountVar - > mAnotherCountVar;

也许这是“静态初始化顺序惨败”的情况, http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.16 ,是因为使用静态成员初始化mCountVar和mAnotherCountVar?

您可以在列表中初始化为零,然后在构造函数的主体中进行赋值。

可能是“静态初始化顺序惨败” ,因为你有公共静态变量和私有构造函数(说明你如何拥有构造函数的公共和私有定义?)。 这些迹象表明这里可能存在与其他类别的依赖关系。

在执行包含类的自身构造函数的主体之前调用成员的构造函数。 构造函数按它们在类中声明的顺序调用,而不是它们在初始化列表中出现的顺序。

为避免混淆,最好按声明顺序指定初始值设定项

成员析构函数按照与构造相反的顺序调用,每个东西都正常工作

class MyClass//**1: mem-init**
{
private:
long number;
bool on;
public:
MyClass(long n, bool ison) : number(n), on(ison) {}
};

MyClass(long n, bool ison) //2 initialization within constructor's body
{
number = n;
on = ison;
}

在MyClass的构造函数的情况下,两种形式之间没有实质性的区别。 这是由于编译器处理mem初始化列表的方式。 编译器扫描mem初始化列表,并在任何用户编写的代码之前将初始化代码插入构造函数的主体中。 因此,第一个示例中的构造函数由编译器扩展到第二个示例中的构造函数中。 尽管如此,在以下四种情况下,在构造函数体内使用mem初始化列表和初始化之间的选择很重要:

  • const成员的初始化
  • 初始化参考成员
  • 将参数传递给基类或嵌入对象的构造函数
  • 成员对象的初始化

我认为整个班级不是直接问题。 你能通过使用这个类生成一个崩溃的最小代码吗? 在我看来,问题是在你的代码库中的其他地方。

但是,你可以添加一个bool Invariant() const; 函数到该类并使用assert(Invariant());调用它(仅在调试版本中assert(Invariant()); 在构造函数的末尾以及进入和退出所有公共函数。 这可能会帮助您“早期崩溃,经常崩溃”,从而指出一些有问题的代码。

这看起来不像你真正的代码。 但请注意,在您的实际代码中,类成员是按照它们在类中定义的顺序构造的,REGARDLESS是构造函数中初始化列表的顺序。 鉴于您提到更改类中成员的顺序会影响问题,这可能是错误的。 例如,您的代码可能会执行以下操作:

class MyClass {
public:
    const int member1;
    const int member2;
    MyClass() {
      : member2(0),
      : member1(member2) // ERROR: this runs first because member1 is defined first
                      // member2 not yet constructed; assigns undefined value to member1
    {}
};

你发布的代码中没有任何异常。 IInterface构造函数中的任何一个都失败了,或者其他东西完全出错了。 也许你在某个地方有一个缓冲区溢出,它正在读取你正在改变结构顺序的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM