调用拷贝构造函数的几种情况

当类中成员有指针变量、类中有动态内存分配时常常需要用户自己定义拷贝构造函数。

在什么情况下系统会调用拷贝构造函数:

(1)用类的一个对象去初始化另一个对象时
(2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用
(3)当函数的返回值是类的对象或引用

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Test
{
public:
int a;
Test(int i):a(i)
{
cout<<a<<'\t' << "构造函数" << endl;
}
~Test()
{
cout<<a<<'\t' << "析构函数"<<endl;
}
Test(const Test &b)
{
a = b.a;
cout << b.a <<'\t'<< "拷贝构造函数" << endl;
}
};

int main()
{
Test a(10);
Test b(20);
Add(a, b);
}

调用函数为值传递

1
2
3
4
5
Test Add(Test a, Test b)
{
auto res = Test(a.a + b.a);
return res;
}

输出为

输出 解释
10 构造函数
20 构造函数 a,b初始化
20 拷贝构造函数
10 拷贝构造函数 形参的拷贝构造,右到左
30 构造函数 Test(a.a + b.a)临时对象
30 拷贝构造函数 赋值给res
30 析构函数 Test(a.a + b.a)临时对象析构
10 析构函数
20 析构函数 形参析构
30 析构函数 返回值res的析构函数
20 析构函数
10 析构函数 a,b析构函数

参数为引用传递

1
2
3
4
5
Test Add(Test& a, Test& b)
{
auto res = Test(a.a + b.a);
return res;
}
输出 解释
10 构造函数
20 构造函数 a,b 初始化
30 构造函数 Test(a.a + b.a)临时变量初始化
30 拷贝构造函数 res的复制构造(值传递)
30 析构函数 临时对象析构
30 析构函数 res析构
20 析构函数
10 析构函数 a,b析构

返回值为引用

1
2
3
4
5
Test& Add(Test& a, Test& b)
{
auto res = Test(a.a + b.a);
return res;
}
输出 解释
10 构造函数
20 构造函数
30 构造函数 res 是 临时对象的引用,因此不会拷贝构造
30 析构函数
20 析构函数
10 析构函数