析:
第一次构造函数:声明 [对象p_3] 时调用;
第二次构造函数:函数体中声明 [对象p] 时调用;
第三次拷贝构造:将函数体中声明的 [对象p] 的数据拷贝给一个 [临时对象] 时调用(如果把类中 移动构造函数的注释去掉
,那么是不会调用拷贝构造函数的,而是调用移动构造函数);
第四次析构函数:函数体中声明的 [对象p] 被析构时调用;
第五次赋值函数:是将 [临时变量] 的数据复制给 [对象p_3] 时调用;
第六次析构函数:[临时变量] 完成拷贝构造之后,调用析构函数,释放所占内存。
为什么不直接调用拷贝构造就完事了呢?
?在 【4.3.1 测试代码-1】中可知,用函数返回的对象来初始化新对象时只需要调用一次拷贝构造或移动构造就行,是不存在复制函数被调用的情况,那为什么4.3.2 测试代码-2就需要调用?
原因剖析:
?原因一:执行Person p_3
导致创建了 [对象p_3] ,而函数返回的也是一个被创建的对象(不是匿名函数),在两个已存在对象之间使用=
是赋值操作,是不会调用拷贝构造或移动构造的。
?原因二:由于原因一,导致函数返回的 [对象p] 没用被使用,函数返回的 [对象p] 会被析构函数释放其所占内存。
?因为原因二会导致函数返回的 [对象p] 会被析构,注意此时都还没有赋值给 [对象p_3] 咧,所以 [对象p] 在析构之前需要把 [对象p] 的数据拷贝给一个 [临时对象] (调用拷贝构造)
,完成拷贝之后 [对象p] 就被析构。最后把 [临时对象] 的数据赋值给已存的 [对象p_3] 即可 (调用赋值函数)
,完成赋值之后 [临时对象] 就被析构。
?至此上面的所有步骤分析完成。
4.4 测试 f_4 函数(函数返回值测试 -- 匿名对象)
Person f_4() { return Person(); }
测试代码:
Person p_4 = f_4();
运行结果:
结果分析:
声明 [对象p_4] 的同时直接使用 [匿名对象] 去初始化,此时 [匿名对象] 会直接转化成 [有名对象p_4]
(匿名对象使用情况2),所以就这个情况而已不会调用拷贝构造函数和移动构造函数。
如果是如下分开情况(先声明,再用匿名对象赋值):
Person p_4;
p_4 = f_4();
运行结果:
结果分析:
第一个默认构造:声明 [对象p_4] 时调用;
第二个默认构造:函数体中的 [匿名对象] 被创建时调用的;
第三个赋值函数:[匿名对象] 赋值给已存在的 [对象p_4] 时调用(匿名对象使用情况3,用匿名对象来赋值给已存在对象时,此时会发生赋值构造,是会调用赋值函数的,同样执行完该行之后匿名对象所占内存被释放);
第四个析构函数:完成赋值之后,[匿名对象] 所占内存被释放时调用。
5. 完整测试代码
点击展开完整测试代码
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class Person
{
public:
// 析构函数
~Person() { std::cout << "destroy...\n"; }
// 默认构造函数
Person() { std::cout << "default constructor...\n"; }
// 拷贝构造函数
Person(const Person& p) { std::cout << "copy constructor...\n"; }
// 移动构造函数
//Person(Person&& p) { std::cout << "move constructor...\n"; }
// 赋值函数
Person& operator=(const Person& p) {
std::cout << "assign function...\n";
return *this;
}
};
// 1.调用拷贝构造函数
void f_1(Person p) {}
// 2.不会调用拷贝构造函数
void f_2(Person& p) {}
// 3.调用默认构造函数
Person f_3() {
Person p;
return p;//注意p它是一个将亡值(右值的一种)
}
// 4.调用默认构造函数
Person f_4() { return Person(); }
int main()
{
//Person();
//Person p = Person();
cout << "------测试f_1函数------\n";
Person p_1;
f_1(p_1);
cout << "-----------------------\n\n";
cout << "------测试f_2函数------\n";
Person p_2;
f_2(p_2);
cout << "----------------------\n\n";
cout << "------测试f_3函数------\n";
Person p_3;
p_3 = f_3();
//Person p_3 = f_3();
cout << "----------------------\n\n";
cout << "------测试f_4函数------\n";
Person p_4 = f_4();
cout << "----------------------\n\n";
return 0;
}