初始化构造函数中的字段 - 初始化列表与构造函数体

时间:2012-03-28 07:51:57

标签: c++ parameters

我一直在用c ++工作一段时间,但我不确定

之间的区别
public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

我觉得他们做同样的事情,但这两种语法之间存在实际差异。其中一个比另一个更安全,它们是否以不同方式处理默认参数。

并不完全习惯于第一个例子,所以如果我犯了错误,我道歉。

6 个答案:

答案 0 :(得分:57)

如果member1member2是非POD(即非 P lain ,则它们不一样O ld D ata )类型:

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

相当于

public : Thing(int _foo, int _bar) : member1(), member2(){
    member1 = _foo;
    member2 = _bar;
}

因为它们将在构造函数体开始执行之前被初始化,所以基本上两次完成工作。这也意味着,如果这些成员的类型没有默认构造函数,那么您的代码将编译。

答案 1 :(得分:13)

第一个是推荐的最佳实践,因为它更惯用,并且避免重新初始化具有默认构造函数的类型的字段(即非基本类型)。

当你只在构造函数体内初始化一个成员时,如果可以,编译器会为你生成一个默认的成员初始化语句,所以你最终会加倍地初始化它。在某些情况下,这可能不是什么大问题,但如果构造对象很昂贵,可能会造成严重的性能开销。

更新

但是,没有(n显式定义或生成的)默认构造函数的用户定义类型无法以这种方式初始化,因此会产生编译器错误。 const和引用字段也是如此 - 这些只能在成员初始化列表中显式初始化。

答案 2 :(得分:6)

唯一要添加到Péter Török的答案是初始化列表是初始化对象的const成员的唯一方法,即:

class foo
{
public:

    foo(int value)
        : myConstValue(value)
    {};

    foo()
    {
        myConstValue = 0; // <=== Error! myConstValue is const (RValue), you can't assign!
    };

private:
    const int myConstValue;
}

答案 3 :(得分:4)

在您的示例代码中,构造函数初始化中的第一个和构造函数体内的赋值。

构造函数初始化列表是执行所有成员初始化的最佳方法,因为它可以提高性能。

class A
{
string name;
public:
A(string myname):name(myname) {}
}

在上面的情况下,编译器不会创建临时对象来进行初始化。但是在以下情况中:

A::A()
{
    name = myname;
}

创建一个单独的临时对象,并将此临时对象传递给string的赋值运算符以分配给name。然后,临时对象被破坏,效率不高。

注意:必须在构造函数初始化列表中初始化引用或const成员。它们不能在构造函数的主体中“分配”。

答案 4 :(得分:2)

除了其他答案之外,我想提一下构造函数初始化仅用于初始化 成员变量。

class Demo
{
    int a;
    int b;
public:
    Demo(int a,int b):a(a),b(b)
    {

    }

};

如果我们初始化a和b内部构造函数,它将是自我赋值。

答案 5 :(得分:1)

首先是初始化,使用初始化列表,第二个是默认构造,然后是赋值。第一个至少与第二个一样快,并且优于第二个。