性能优化
在刚接触c++时候就觉得c++很有意思,比如在c中用”=”赋值的一些语句可以使用”()”进行初始化,但是之前并没有十分理解初始化相比于赋值语句有什么优点,后来在学习了类之后,初始化列表的出现,让我对初始化有了更加深刻的理解。
首先看代码
#include<iostream>
using namespace std;
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)
{
test1 = t1;
}
};
int main()
{
Test1 t1;
Test2 t2(t1);
}
其运行需要3步:
而当我们将Test2的构造函数改为
Test2(Test1 &t1) : test1(t1)
{}
其结果为,只需要进行两步
可见在类的的构造的时候使用初始化列表的可以通过减少函数调用的次数,从而使得性能得到优化
成员变量的初始化
初始化列表虽然在性能优化上面有作用之外,但是在使用时也存在一些坑点。
比如:
#include<iostream>
using namespace std;
struct Test
{
Test(int x) : t2(x), t1(t2)
{}
int t1, t2;
};
int main()
{
Test t(2);
}
我们借助vs查看对象t的成员t1,和t2的值分别为
可见初始化列表中初始化的顺序和在初始化列表中的顺序 没有关系,咱们可以把Test的构造函数再更改一下:
struct Test
{
Test(int x) : t2(x++), t1(x++)
{}
int t1, t2;
};
从此例可以明显的看出程序时先给t1初始化然后在为t2初始化。
我们可以得出结论成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的,上例当中的t2在t1之后定义,因此再给t1初始化时t2还未创建因此t1的值为随机值。
必须使用初始化列表的情况
- 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
- 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
- 没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
我们举例说明一下
1.常量成员
const int MAX = 10; //这种情况下必须进行初始化,否则编译不通过。在vs中的报错为 “MAX”: 如果不是外部的,则必须初始化常量对象
2.引用类型
int i;
int &t = i; //若不进行初始化,报错为 “t”: 必须初始化引用
3.没有默认构造函数的类类型
struct Test
{
Test(int x) : t2(x), t1(x++)
{}
int t1, t2;
};
int main()
{
Test t; //此时编译无法通过,因为在Test类当中没有无参的构造函数,因此必须使用初始化
}