在这个特定的情况下,使用成员初始值设定项列表和在构造函数中赋值有什么不同?
在内部和关于生成的代码,之间有一个真正的区别:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0) { }
和
MyClass::MyClass() { _capacity=15; _data=NULL; _len=0 }
谢谢…
假设这些值是原始types,那么不,没有区别。 初始化列表只有当您有对象作为成员时才会有所作为,因为不是使用默认初始化,而是使用赋值,初始化列表允许您将对象初始化为其最终值。 这实际上可以明显更快。
你需要使用初始化列表来初始化常量成员,引用和基类
当你需要初始化常量成员,引用和传递参数给基类构造函数时,如注释所述,你需要使用初始化列表。
struct aa { int i; const int ci; // constant member aa() : i(0) {} // will fail, constant member not initialized }; struct aa { int i; const int ci; aa() : i(0) { ci = 3;} // will fail, ci is constant }; struct aa { int i; const int ci; aa() : i(0), ci(3) {} // works };
示例(非穷举)类/结构体包含引用:
struct bb {}; struct aa { bb& rb; aa(bb& b ) : rb(b) {} }; // usage: bb b; aa a(b);
初始化需要参数的基类的例子(例如,没有默认的构造函数):
struct bb {}; struct dd { char c; dd(char x) : c(x) {} }; struct aa : dd { bb& rb; aa(bb& b ) : dd('a'), rb(b) {} };
是。 在第一种情况下,你可以声明_capacity
, _len
和_len
作为常量:
class MyClass { private: const int _capacity; const void *_data; const int _len; // ... };
如果要在运行时计算它们的值时确保这些实例variables的一致性,这将非常重要,例如:
MyClass::MyClass() : _capacity(someMethod()), _data(someOtherMethod()), _len(yetAnotherMethod()) { }
const
实例必须在初始化程序列表中初始化, 或者底层types必须提供公共无参数构造函数(基本types)。
我会补充一点,如果你有没有默认构造函数的类types的成员,初始化是构造你的类的唯一方法。
我想这个链接http://www.cplusplus.com/forum/articles/17820/给出了一个很好的解释; – 特别是对于那些新的C ++。
intialiser列表更有效的原因是,在构造函数体内,只有分配,而不是初始化。 因此,如果您正在处理非内置types,则在input构造函数的主体之前,该对象的默认构造函数已被调用。 在构造函数体内,您正在为该对象分配一个值。
实际上,这是对默认构造函数的调用,然后是对复制赋值运算符的调用。 初始化列表允许你直接调用复制构造函数,这有时会显着加快(回想起初始化列表在构造函数的主体之前)
最大的区别是赋值可以初始化父类的成员; 初始化程序只对在当前类范围声明的成员有效。
取决于涉及的types。 之间的差异是相似的
std::string a; a = "hai";
和
std::string a("hai");
第二种forms是初始化列表 – 也就是说,如果types需要构造函数参数,或者对于构造函数参数更有效,则会有所不同。
真正的区别归结为gcc编译器如何生成机器码和放下内存。 说明:
- (phase1)在init主体(包括init列表)之前:编译器为类分配所需的内存。 这个class还活着!
- (阶段2)在init主体中:由于内存被分配,所以每个赋值现在都表示已经退出/“初始化”variables的操作。
当然还有其他方法来处理consttypes的成员。 但为了减轻他们的生活,海湾合作委员会的编译器决定build立一些规则
- consttypes成员必须在init主体之前初始化。
- 阶段1之后,任何写操作只对非常量成员有效。
只有一种方法来初始化基类实例和非静态成员variables,并且使用初始化器列表。
如果你没有在你的构造函数的初始化列表中指定一个基本的或非静态的成员variables,那么该成员或基础将被默认初始化(如果成员/基类是非POD类types或非POD类的数组types),否则保持未初始化。
一旦构造函数体被input,所有的基础或成员将被初始化或保持未初始化(即它们将具有不确定的值)。 构造函数体中没有机会影响它们应该如何初始化。
您可能可以在构造函数体中为成员赋予新的值,但是不可能将其赋值给不可赋值的类成员或类成员,并且不可能重新引用引用。
对于内置types和一些用户定义的types,在构造函数体中的赋值可能具有与在初始值设定项列表中使用相同值进行初始化完全相同的效果。
如果在初始化程序列表中没有命名成员或基地,并且该实体是引用,具有没有可访问的用户声明的默认构造const
类types,则为const
限定的并具有PODtypes,或者是POD类types或POD类数组包含一个const
限定成员(直接或间接)的types,那么该程序是格式不正确的。
如果你写一个初始化列表,你只需要一步步完成。 如果你不写一个initilizer列表,你会做2个步骤:一个用于声明,另一个用于赋值。
初始化列表和初始化语句在构造函数中是有区别的。 让我们考虑下面的代码:
#include <initializer_list> #include <iostream> #include <algorithm> #include <numeric> class MyBase { public: MyBase() { std::cout << __FUNCTION__ << std::endl; } }; class MyClass : public MyBase { public: MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) { std::cout << __FUNCTION__ << std::endl; } private: int _capacity; int* _data; int _len; }; class MyClass2 : public MyBase { public: MyClass2::MyClass2() { std::cout << __FUNCTION__ << std::endl; _capacity = 15; _data = NULL; _len = 0; } private: int _capacity; int* _data; int _len; }; int main() { MyClass c; MyClass2 d; return 0; }
当使用MyClass时,所有成员将在执行构造函数中的第一个语句之前被初始化。
但是,当使用MyClass2时,当构造函数中的第一条语句执行时,所有成员都不会被初始化。
在以后的情况下,在某个成员被初始化之前,有人在构造函数中添加了一些代码时,可能会出现回归问题。