47

我知道使用初始化列表的好处是它们在初始化非内置类成员时提供了效率。例如,

Fred::Fred() : x_(whatever) { }

更可取的是,

Fred::Fred() { x_ = whatever; }

如果 x 是自定义类的对象。除此之外,为了保持一致性,这种风格甚至与内置类型一起使用。

这样做最常见的好处是提高了性能。如果表达式whatever 与成员变量x_ 的类型相同,则whatever 表达式的结果直接在x_ 内部构造——编译器不会制作对象的单独副本。

对于另一种风格,表达式whatever 会导致创建一个单独的临时对象,并且这个临时对象被传递给x_ 对象的赋值运算符。然后该临时对象在 ; 处被破坏。那是低效的。

问题
在以下示例中使用初始化列表是否有任何效率提升。我认为没有收获。第一个版本调用字符串的复制构造函数,另一个调用字符串的赋值运算符(没有创建任何临时的)。对吗?

class MyClass
{
public:
    MyClass(string n):name(n) { }
private:
    string name;
};

class MyClass
{
public:
    MyClass(string n)
    {
        name=n;
    }
private:
    string name;
};
4

5 回答 5

36

第二个版本是调用 string 的默认 ctor,然后是 string 的复制赋值运算符——与第一个版本相比,肯定会有(较小的)效率损失,它直接调用 c 的 copy-ctor(例如,根据 string 的实现,可能会有一些微小结构的无用分配然后释放)。为什么不总是使用正确的方法?-)

于 2009-10-21T06:03:52.510 回答
18

我认为初始化 const 数据成员的唯一方法是在初始化列表中

例如。在标题中:

class C
{
    C();
private:
    const int x;
    int y;
}

而在cpp文件中:

C::C() :
    x( 10 ),
    y( 10 )
{
    x = 20; // fails
    y = 20;
}
于 2009-10-21T08:11:55.230 回答
14

这是初始化成员的好方法:

  • 是常量
  • 没有默认构造函数(它是私有的)
于 2009-10-21T09:25:50.073 回答
12

请记住,复制构造函数和赋值运算符之间存在明显区别:

  • 复制 ctor使用其他实例构造一个新对象,作为从中获取初始化信息的地方。
  • 赋值运算符修改已经完全构造的已经存在的对象(即使它只是通过使用默认构造函数)

因此,在您的第二个示例中,已经完成了一些工作来name创建

 name=n;

到达了。

但是,很可能(特别是在这个简单的示例中)所做的工作非常小(可能只是将string对象中的一些数据成员归零)并且在优化的构建中完全优化了工作。但是尽可能使用初始化列表仍然被认为是一种很好的形式。

于 2009-10-21T06:23:28.943 回答
2

我们还可以通过初始化列表执行构造函数委托。

于 2013-03-19T08:25:39.583 回答