使用初始化列表

时间:2013-03-10 22:04:40

标签: c++ constructor initializer-list

我已经学会了什么是initialization list以及如何use it,但我仍然想知道一件事。

如果有的话,在初始化类的变量之间使用初始化列表或在构造函数中自己执行它有什么区别?

E.g。

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};

VS

class MyClass {
public:

    MyClass(){
        m_classID = -1;
        m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;
};

这只是一种设计习惯,使代码更容易阅读和写入,还是有其他特定原因?

6 个答案:

答案 0 :(得分:2)

如果这些变量是基本类型,并且它们不是const而不是引用,则没有区别。

如果您的成员是引用,或者它是const,那么您将必须初始化它们,而这只能通过初始化列表完成,原因与此相同禁止创建基本类型的未初始化引用或const变量:

int& x; // ERROR!
const int y; // ERROR!

初始化后无法重新分配这些对象:因此,有必要对它们进行值初始化,并且不允许执行类的构造函数的 body 这些成员变量未初始化。

因此,当您有选择时,对于基本类型,两种形式之间没有区别 - 请记住,在某些情况下,可以选择。

另一方面,如果您的成员变量是类类型,那么区别在于没有初始化列表,它们将是默认构造的(如果可能的话)和然后在构造函数体中分配;使用初始化列表,它们将使用您指定的参数直接构造。

请注意,C ++ 11为您提供了额外的可能性:

class MyClass {
public:
    int m_classID = -1;
    void *m_userdata = nullptr;
};

答案 1 :(得分:2)

初始化列表允许您调用成员变量的构造函数。

如果在构造函数的主体中初始化,则调用operator=(赋值),而不是构造函数。

差异类似于这两种形式之间的差异:

int three(3);            // Constructor argument
int three; three = 3;    // Assignment after construction

对于没有默认构造函数(即没有参数的构造函数)的成员,以及在创建它们时必须设置其值的成员(如引用和常量),这会有所不同。

因此,只能在构造函数体中初始化某些成员类型;但是所有类型的成员都可以在初始化列表中初始化。这个,以及没有为初始化程序列表初始化成员调用默认构造函数(这对复杂对象产生影响,但对整数而言无关紧要),这意味着通常最好使用初始化程序列表,给出了选择。

答案 2 :(得分:1)

对于你给出的情况,没有直接的区别 - 初始化程序列表实际初始化(声明成员的顺序)的ORDER略有不同,在第二个例子中,如果你要交换用m_classID=-1m_userdata = 0行,他们确实会以相反的顺序初始化。

您无法初始化初始化列表之外的引用或const值,因此:

class bleh
{
   int& m_x;
   bleh(int x)
   {
      m_x = x;
   }
};

会给你一些错误。

class bleh
{
   int& m_x;
   bleh(int x): m_x(x)
   {
   }
};

是正确的方法。

答案 3 :(得分:1)

只是指出c ++ 11的不同之处:

class MyClass {
public:
    MyClass(std::string str) : m_str(str) { }
private:
    std::string m_str;
};

相当于做

class MyClass {
public:
    MyClass(std::string str) { m_str = std::move(str); }
private:
    std::string m_str;
};

其中:

class MyClass {
public:
    MyClass(std::string str) { m_str = str; }
private:
    std::string m_str;
};

只调用赋值运算符。

我遇到了这个问题,因为我正在初始化Lua中的对象,当它们被破坏时,字符串被清理两次导致sigtrap,因为Lua认为它控制了传入的字符串的所有权,但是一旦它#39 ; s已经不再那样了。

我知道这并没有完全回答这个问题,但其他答案并没有直接解决这个问题。

答案 4 :(得分:0)

有些人在没有MIL的情况下无法初始化,例如参考成员。

class MyClass {
public:

    MyClass(MyOtherClass& otherClass)
         : m_classID(-1)
         , m_userdata(otherClass)
    { 
    }

    int m_classID;
    MyOtherClass& m_userdata;
};

此外,它是使const成员进行intizlize的唯一方法。

答案 5 :(得分:0)

初始化列表更可取,因为

  1. 您可以将它们与参考文献
  2. 一起使用
  3. 你避免运行默认的构造函数+ operator =,只是一个更快的neccecary构造函数。如果默认构造函数是私有的,则必须使用初始化列表