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

时间:2009-09-29 12:18:09

标签: c++ memory constructor initialization

通过使用以下类在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)
{
}

7 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:3)

可以"static initialization order fiasco"判断你有公共静态变量和私有构造函数(说明你如何拥有构造函数的公共和私有定义?)。这些迹象表明这里可能存在与其他类别的依赖关系。

答案 3 :(得分:3)

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

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

成员析构函数按照构造的相反顺序调用,每件事都正常工作

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成员的初始化
  • 参考成员的初始化
  • 将参数传递给基类或嵌入对象的构造函数
  • 成员对象的初始化

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

这看起来不像你的真实代码。但请注意,在您的实际代码中,类成员是按照它们在类中定义的顺序构造的,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
    {}
};

答案 6 :(得分:0)

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