构造函数初始列表与体内赋值辨析
1、初始化列表与赋值区别
1) 初始化代表为变量分配内存,变量在其定义处被编译器初始化(编译时);在函数中, 函数参数初始化发生在函数调用时(运行时)。然而,赋值代表"擦除对象当前值, 赋予新值",不承担为对象分配内存的义务。
2)对于内置类型,初始化列表与体内赋值性能差距不大;但对于复杂的内对象,初始化列表无需调用默认构造函数,从而提高程序性能
eg1:
#include <iostream>
using std::cout;
using std::endl;
struct Test1
{
Test1()
{
cout << "Construct Test1" << endl;
}
Test1(const Test1& t1) //
{
cout << "Copy constructor for Test1" << endl;
this->a = t1.a;
}
Test1& operator = (const Test1& t1)
{
cout << "Assignment for Test1" << endl;
this->a = t1.a;
return *this;
}
int a;
};
struct Test2
{
Test1 test1;
Test2(Test1 &t1)
{
test1 = t1;
}
};
int main(int argc, char* argv[])
{
Test1 t1;
Test2 t2(t1);
return 0;
}
输出结果:
Construct Test1
Copy constructor for Test1
Assignment for Test1
eg2:
#include <iostream>
using std::cout;
using std::endl;
struct Test1
{
Test1()
{
cout << "Construct Test1" << endl;
}
Test1(const Test1& t1) //
{
cout << "Copy constructor for Test1" << endl;
this->a = t1.a;
}
Test1& operator = (const Test1& t1)
{
cout << "Assignment for Test1" << endl;
this->a = t1.a;
return *this;
}
int a;
};
struct Test2
{
Test1 test1;
Test2(Test1 &t1) :test1(t1) {
}
};
int main(int argc, char* argv[])
{
Test1 t1;
Test2 t2(t1);
return 0;
}
输出结果:
Construct Test1
Copy constructor for Test1
比较eg1和eg2的输出结果可知,使用初始化列表减少了一次调用默认构造函数。
注:根据成员在类中声明的顺序决定初始化列表成员的顺序,否则会出现未定义的行为。
2、必须使用初始化列表
1)常量成员
常量只能初始化,不能赋值
eg:
class A
{
const int x;
public:
A( ){
this->x = 1;
}
};
等价于:
const int x;
x = 1;
正确方式:
class A
{
const int x;
public:
A() : x(1){
}
};
2)引用成员
引用必须在定义时初始化,且初始化后不能重新赋值
eg:
class A {
int &x;
public:
A(int k) {
this->x = k;
}
};
等价于:
int &x;
int k;
x = k;
正确方式:
class A {
const int x;
public:
A(int k) : x(k) {
}
};
3)没有默认构造函数的类类型
初始化列表不需要调用构造函数初始化,而是直接调用拷贝构造函数初始化
eg:
struct Test1
{
Test1(int a) :i(a) {}
int i;
};
struct Test2
{
Test1 test1;
Test2(Test1 &t1)
{
test1 = t1;
}
};
正确方式:
struct Test1
{
Test1(int a) :i(a) {}
int i;
};
struct Test2
{
Test1 test1;
Test2(Test1 &t1) :test1(t1) {}
};
3、选择规则
1) 所有static成员变量在类外初始化(不管它是const,是引用,还是没默认构造函数的对象)
2)对于常量成员、引用成员及没有默认构造函数的类类型必须在初始化列表初始化
3)需要复杂运算及资源分配时,使用在构造函数内赋值;否则,尽量在初始化列表中初始化。
参考文献
[1] C++类构造函数初始化列表. http://www.cnblogs.com/BlueTzar/articles/1223169.html.
[2]【深入理解C++】从初始化列表和构造函数谈C++的初始化机制. http://blog.csdn.net/theprinceofelf/article/details/20057359.
[3] 成员初始化列表与构造函数体中的区别详细解析. http://www.jb51.net/article/41812.htm.
[4] 我所理解的构造函数的初始化列表(转). http://blog.sina.com.cn/s/blog_4c5c3e0501000am7.html.
[5] Constructorinitialization Vs assignment. http://stackoverflow.com/questions/15679977/constructor-initialization-vs-assignment.
[6] initializationlists vs explicit assignment. http://www.cplusplus.com/forum/general/114874/.
[7] c++初始化列表及构造函数调用构造函数. http://blog.csdn.net/mrluoming/article/details/7614042.
[8]C++初始化列表. http://www.cnblogs.com/graphics/archive/2010/07/04/1770900.html.
注:为了便于自己学习,无心侵权,尽可能将所引用的文章列举出来;有些文章的内容可能会与原作重复度较高,还请谅解。如作者举报,愿意删除此文。