初始化列表的好处
我所知道的使用初始化列表的好处是,它们在初始化非内置的类成员时提供效率。 例如,
Fred::Fred() : x_(whatever) { }
优于,
Fred::Fred() { x_ = whatever; }
如果x是自定义类的对象。 除此之外,为了保持一致性,甚至使用内置types也使用此样式。
这样做的最普遍的好处是提高了性能。 如果expression式与成员variablesx_的types相同,则expression式的结果直接在x_内部构造 – 编译器不会创build对象的单独副本。
使用其他样式,expression式会导致创build一个单独的临时对象,并将此临时对象传递给x_对象的赋值运算符。 然后那个临时对象被破坏了。 这是无效的。
题
在使用初始化列表的下面的例子中是否有任何效率增益。 我认为没有收获。 第一个版本调用string的复制构造函数,另一个调用string的赋值运算符(没有任何临时的创build)。 这是正确的?
class MyClass { public: MyClass(string n):name(n) { } private: string name; }; class MyClass { public: MyClass(string n) { name=n; } private: string name; };
第二个版本是调用string的默认ctor,然后是string的复制赋值运算符 – 与第一个版本相比,可以肯定会有(较小的)效率损失,直接调用c的copy-ctor(例如,根据string的实现,可能会无用的分配 – 然后释放一些微小的结构)。 为什么不总是使用正确的方式?)
我认为初始化常量数据成员的唯一方法是在初始化列表中
例如。 在标题中:
class C { C(); private: const int x; int y; }
而在cpp文件中:
C::C() : x( 10 ), y( 10 ) { x = 20; // fails y = 20; }
这是初始化成员的好方法:
- 是常量
- 没有默认的构造函数(它是私有的)
请记住,复制构造函数和赋值运算符有明显的区别:
- copy ctor使用其他实例构造一个新的对象作为获取初始化信息的地方。
- 赋值运算符修改已经完全构build的已经存在的对象(即使它只是使用默认的构造函数)
所以在你的第二个例子中,已经做了一些工作来创buildname
name=n;
到达了。
然而,这是很有可能的(特别是在这个简单的例子中)所做的工作是微乎其微的(可能只是清理string
对象中的一些数据成员),并且工作在优化构build中完全优化。 但是尽可能地使用初始化列表仍然是一种很好的forms。
以下是使用初始化程序列表的场景:
- 用于初始化非静态常量数据成员。
- 用于初始化参考成员。
- 用于初始化没有默认构造函数的成员对象。
- 用于基类成员的初始化。
- 当构造函数的参数名称与数据成员相同时。
- 出于性能原因。
我们也可以通过初始化列表来执行构造函数的委托 。