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

gar*_*n06 48 c++ parameters

我一直在用c ++工作一段时间,但我不确定它们之间的区别

public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}
Run Code Online (Sandbox Code Playgroud)

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Luc*_*ore 63

他们是不一样的,如果member1member2是非POD(即非P LAIN Ø LD d ATA)类型:

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}
Run Code Online (Sandbox Code Playgroud)

相当于

public : Thing(int _foo, int _bar) : member1(), member2(){
    member1 = _foo;
    member2 = _bar;
}
Run Code Online (Sandbox Code Playgroud)

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

  • *工作完成两倍*,不是真的.这只是更多的工作,而不是工作的两倍. (2认同)

Pét*_*rök 13

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

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

更新

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

  • 然后编译器不高兴。此外 - 初始化列表是初始化对象的 `const` 字段的唯一方法。 (2认同)

Pap*_*ter 8

添加到PéterTö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;
}
Run Code Online (Sandbox Code Playgroud)


San*_*ish 6

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

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

class A
{
string name;
public:
A(string myname):name(myname) {}
}
Run Code Online (Sandbox Code Playgroud)

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

A::A()
{
    name = myname;
}
Run Code Online (Sandbox Code Playgroud)

创建一个单独的临时对象,并将该临时对象传递给string的赋值运算符来赋值给name。然后临时对象就被销毁了,效率不太高。

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