C++初始化列表的效率问题
在C++11中引入了初始化列表的方式,很多人都知道初始化列表是为了提高效率的,但是并不清楚是如何提高效率的,就知道怎么用,并不知道原理,这就是一个程序员的大忌!
什么情况下必须使用初始化列表
- 在引用类型的时候必须使用初始化列表,因为引用类型是不能修改的
- 在const修饰的变量下,因为const变量也是不可以修改的
- 类中含有成员函数,并且该成员函数没有无参构造却有有参构造,因为在这种情况下编译器只会自动调用成员类的无参构造,但是你没有无参构造就会报错,就只有使用初始化列表
- 继承关系,父类没有无参构造,但是有有参构造,理由和第三条一样
初始化列表的执行流程
先来一个demo代码
#include <iostream>
class A
{
public:
A()
{
std::cout << "构造函数" << std::endl;
}
A(int a)
{
std::cout << a << std::endl;
}
public:
int a;
};
class B
{
public:
B():tempa(1), tempb(2) {}
public:
A tempb;
A tempa;
A tempc;
};
int main()
{
B b;
return 0;
}
把这串代码跑起来,输出
2
1
构造函数
根据例子和输出可以得到结论
- 初始化列表并不是根据你写的顺序来运行的,而是根据你定义变量的顺序来初始化的
- 如果变量你写了初始化列表,那么他会按照你写的初始化去执行,如果你没有写,那么会默认调用默认构造函数
效率问题
没有使用初始化列表时
#include <iostream>
class A
{
public:
A()
{
std::cout << "A构造函数" << std::endl;
}
A& operator=(const A& _a)
{
std::cout << "A赋值构造" << std::endl;
this->a = _a.a;
return *this;
}
public:
int a;
};
class B
{
public:
B() { std::cout << "B构造函数" << std::endl; }
B(const A& a)
{
this->tempb = a;
std::cout << "B拷贝构造" << std::endl;
}
public:
A tempb;
};
int main()
{
A a;
B b(a);
return 0;
}
编译器输出:
A构造函数
A构造函数
A赋值构造
B拷贝构造
我的拷贝构造 复制构造并不规范,请忽略!
使用了初始化列表时
#include <iostream>
class A
{
public:
A()
{
std::cout << "A构造函数" << std::endl;
}
A& operator=(const A& _a)
{
std::cout << "A赋值构造" << std::endl;
this->a = _a.a;
return *this;
}
A(const A& _a)
{
this->a = _a.a;
std::cout << "A拷贝构造" << std::endl;
}
public:
int a;
};
class B
{
public:
B() { std::cout << "B构造函数" << std::endl; }
B(const A& a) :tempb(a)
{
std::cout << "B拷贝构造" << std::endl;
}
public:
A tempb;
};
int main()
{
A a;
B b(a);
return 0;
}
输出:
A构造函数
A拷贝构造
B拷贝构造
我的拷贝构造 复制构造并不规范,请忽略!
应该很轻易的就发现区别,你需要对默认构造、拷贝构造、复制构造的调用时机非常熟悉才能看得出来问题出在在哪里;
简单的说一下区别就在:你没有使用初始化成员列表的时候他也调用了一次默认构造来初始化你的类成员,然后你由接着去赋值,多执行了一次默认构造,你完全可以直接执行拷贝构造函数的。
总结
- 对于基本数据类型、指针、引用这些时,初始化成员列表并没有什么很大的提升,但是使用自定义类型时,效率会得到很大的提升,可以少调用一次无参构造
- 必须要清楚初始化列表的执行顺序,以免初始化为一个没有初始化的变量