对应的是c++primer 第五版P447的练习13.13
代码里加入了一些自己的理解,分享另一种思考问题的方法
#include <iostream>
#include <vector>
using namespace std;
struct X {
X() { cout << "X()" << endl; }
X(const X&) { cout << "X(const X&)" << endl; }
X& operator=(X& g)
{
cout << "X& operator=(const X&)" << endl;
return *this;
}
~X()
{
cout << "~X()" << endl;
}
}a,b;
int function(X a,X &b)
{
return 0;
}
int main()
{
function(a, b);//传递参数时a拷贝构造,不是拷贝赋值,函数调用结束局部变量a离开了作用域调用了析构函数,而引用b还在
X* p = new X(a);//new X(a)时,在new分配的动态空间里发生了 拷贝构造(new分配一个X类型的动态空间,用a构造初始化)所以输出"X(const X&)"
vector<X> vec = { *p };//这里输出了两次"X(const X&)",说明调用了两次拷贝构造函数,
//第一次为=右边花括号初始化类产生的(联想一下基类的初始化 struct ={})*p指向的类作为参数传递给拷贝构造函数产生一个临时的类对象(说明vector有能接受一个元素的构造函数)
//这里有一个比较重要的知识点:编译器跳过了拷贝赋值函数,直接调用拷贝构造函数例如
//string null_book="999-99999";
//改写为
//string null_book("999-99999");
//这里很明显编译器跳过了拷贝赋值函数,直接进入拷贝构造函数
//对vec里的元素进行拷贝构造(这个临时对象很快就被析构了)注意虽然=右边是类对象,但是没有调用operator=函数
//第二次为vector容器里X类型元素的初始化,初始化完之后析构上面提到的临时变量
//拷贝构造函数会逐元素地拷贝一个数组类型的成员,如果数组元素是类类型,则使用元素的拷贝赋值函数来进行拷贝
a = { *p };//这里调用了operator=拷贝赋值函数而且没有调用析构函数说明没有临时变量产生,推测表达式可以换为 a=*p ,说明vector和普通的类在花括号的使用上面还有区别
a = b;//调用拷贝赋值函数(operator=),类似shared_ptr之间的拷贝(shared_ptr本来就是一个类,= 左边的引用计数减一,右边加一)注意不会析构a,a依然存在
delete p;
}
```cpp
#include <iostream>
using namespace std;
struct st {
st(int i,int j,int k):i(i),j(j),k(k) { cout << 114514; }
~st() { cout << 1919810; }
int i, j, k;
};
int main()
{
st s1 = { 1,2,3 };//相当于调用st s(1,2,3);
st s2(1, 2, 3);//结果相同
//所以这就很好地解释了为什么vector<X> vec = { *p };这个语句调用的是拷贝构造函数 X(const X&) 而不是拷贝赋值函数 X& operator=(X& g) 花括号转换为了圆括号 执行拷贝构造函数
//而a = { *p }单纯忽略了括号,直接执行拷贝赋值函数
}
``