复制构造函数
来源:互联网 发布:ae cs6 mac汉化破解版 编辑:程序博客网 时间:2024/06/07 06:27
以下代码全都是在VS2015的Debug模式下运行的,使用其他编译器可能会结果不一样,比如g++就不是这样。
先看下面的代码:
//code 1#include <iostream>using namespace std;class Resource {public: Resource() { cout << "Resource Constructor!" << endl; } ~Resource() { cout << "Resource Destructor!" << endl; }};class Test {public: Test() { p = new Resource(); cout << "Test Constructor!" << endl; } Test(Test& t) { p = new Resource(); cout << "Test Copy Constructor!" << endl; } ~Test() { if (p != nullptr) { cout << "p is not null!" << endl; delete p; } else { cout << "p is null!" << endl; } cout << "Test Destructor!" << endl; } Resource* p;};Test goo() { Test t; return t;}int main() { goo(); cout<<"end"<<endl; return 0;}
在我的VS2015上以Debug模式运行的话,其运行结果是:
Resource Constructor!
Test Constructor!
Resource Constructor!
Test Copy Constructor!
p is not null!
Resource Destructor!
Test Destructor!
p is not null!
Resource Destructor!
Test Destructor!
end
这里面的流程:
1. 首先调用Test的构造函数构造t,
2. 然后使用其复制构造函数构造foo函数的返回值,
3. 然后离开foo函数时,调用Test的析构函数析构变量t,
4. 在main函数中调用goo函数返回值的析构函数
5. 打印 end
6. 离开main函数
这里可见,goo函数返回的临时值在第一次使用后就立刻被析构了,这是一个右值。同时可以看到,这里Resource被分配了两次,分别是步骤2和步骤3中构造的。
下面修改一下代码:
// code 2#include <iostream>using namespace std;class Resource {public: Resource() { cout << "Resource Constructor!" << endl; } ~Resource() { cout << "Resource Destructor!" << endl; }};class Test {public: Test() { p = new Resource(); cout << "Test Constructor!" << endl; } Test(Test& t) { p = new Resource(); cout << "Test Copy Constructor!" << endl; } ~Test() { if (p != nullptr) { cout << "p is not null!" << endl; delete p; } else { cout << "p is null!" << endl; } cout << "Test Destructor!" << endl; } Resource* p;};Test goo() { Test t; return t;}int main() { Test t(goo());//change cout<<"end"<<endl; return 0;}
在没运行之前,我觉得运行结果应该是这样:
Resource Constructor!
Test Constructor!
Resource Constructor!
Test Copy Constructor!
p is not null!
Resource Destructor£¡
Test Destructor!
Test Copy Constructor!
p is not null!
Resource Destructor£¡
Test Destructor!
end
p is not null!
Resource Destructor£¡
Test Destructor!
我当时内心想的流程是这样的:
1. 首先goo函数内部构造t,调用其构造函数
2. 然后使用复制构造函数构造goo函数的返回值,调用复制构造函数
3. 然后对goo内部的t调用析构函数
4. 在main函数内部,对t调用复制构造函数(移动复制构造函数后面再说),复制参数就是goo函数的返回值
5. 对goo函数的返回值调用析构函数
6. 打印 end
7. 离开main函数,调用main函数中的t的析构函数
而实际上,其运行结果如下:
Resource Constructor!
Test Constructor!
Resource Constructor!
Test Copy Constructor!
p is not null!
Resource Destructor£¡
Test Destructor!
end
p is not null!
Resource Destructor£¡
Test Destructor!
跟我之前预期的不一样,感觉像是没有对goo函数的返回结果进行构造,而是直接用返回值(这里不准确,感觉返回值都没有构造,感觉像是直接用goo里面的t)对main函数中的t进行了复制构造。在我之前的译文C++中的右值引用中,里面有这样一句话:
任何一个现代编译器都会对原始的那个函数定义应用返回值优化。换句话说,编译器会直接在foo返回值的位置构造一个X对象,而不是在内部构造一个X对象然后将它复制出去。
如果按照这个规则,代码2很好解释,但是代码1就很难解释,因为代码1的运行结果显示,真的在函数内部构造一个Test对象,然后对函数的返回值进行了复制。关于这个问题,我现在还不太清楚,感觉需要查看汇编来查看。汇编我以后再写。
言归正传,下面再修改一些代码,对Test类增加移动语义:
// code 3#include <iostream>using namespace std;class Resource {public: Resource() { cout << "Resource Constructor!" << endl; } ~Resource() { cout << "Resource Destructor!" << endl; }};class Test {public: Test() { p = new Resource(); cout << "Test Constructor!" << endl; } Test(Test& t) { p = new Resource(); cout << "Test Copy Constructor!" << endl; } Test(Test&& t) {//change p = t.p; t.p = nullptr; cout << "Test Move Copy Constructor!" << endl; } Test& operator=(Test&& t) {//change Resource *ptr = p; p = t.p; t.p = ptr; cout << "Test Move Assignment Operator!" << endl; return *this; } ~Test() { if (p != nullptr) { cout << "p is not null!" << endl; delete p; } else { cout << "p is null!" << endl; } cout << "Test Destructor!" << endl; } Resource* p;};int main() { goo(); cout<<"end"<<endl; return 0;}
这里对类Test加入了移动复制构造函数,运行结果如下:
Resource Constructor!
Test Constructor!
Test Move Copy Constructor!
p is null!
Test Destructor!
p is not null!
Resource Destructor£¡
Test Destructor!
end
这里面的流程是:
1. 首先使用Test的构造函数构造t
2. 然后使用Test的移动复制构造函数构造goo函数的返回值
3. 对goo函数中的t进行析构
4. 在main函数中对goo函数的返回值进行析构
5. 打印 end
6. 离开main函数
这里可以看出,在构造goo函数的返回值时,优先使用了移动复制构造函数,这样的话,减少了一次内部资源的分配(Resource只分配了一次),其余和代码1都一样。
下面再修改一下代码:
// code 4#include <iostream>using namespace std;class Resource {public: Resource() { cout << "Resource Constructor!" << endl; } ~Resource() { cout << "Resource Destructor!" << endl; }};class Test {public: Test() { p = new Resource(); cout << "Test Constructor!" << endl; } Test(Test& t) { p = new Resource(); cout << "Test Copy Constructor!" << endl; } Test(Test&& t) { p = t.p; t.p = nullptr; cout << "Test Move Copy Constructor!" << endl; } Test& operator=(Test&& t) { Resource *ptr = p; p = t.p; t.p = ptr; cout << "Test Move Assignment Operator!" << endl; return *this; } ~Test() { if (p != nullptr) { cout << "p is not null!" << endl; delete p; } else { cout << "p is null!" << endl; } cout << "Test Destructor!" << endl; } Resource* p;};int main() { Test t;//change t = goo();//change cout<<"end"<<endl; return 0;}
这里的运行结果是:
Resource Constructor!
Test Constructor!
Resource Constructor!
Test Constructor!
Test Move Copy Constructor!
p is null!
Test Destructor!
Test Move Assignment Operator!
p is not null!
Resource Destructor£¡
Test Destructor!
end
p is not null!
Resource Destructor£¡
Test Destructor!
读者可以按照上面的思想自己思考流程。
在代码4的基础上,如果我将移动赋值操作符重载改成下面这样:
Test& operator=(Test&& t) { p = t.p; out << "Test Move Assignment Operator!" << endl; return *this;
运行后会发生什么?
- 构造函数 复制构造函数
- 深复制-复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 学习复制构造函数
- 复制构造函数
- 复制构造函数
- 复制构造函数
- 复制构造函数
- 复制构造函数总结
- 复制构造函数
- 复制构造函数
- C++复制构造函数
- 复制构造函数实例
- 复制构造函数
- leetcode_sicily
- android属性动画实现翻卡片抽奖
- 数学问题——找“亲密数”
- 为什么我们道歉
- 数据库复习
- 复制构造函数
- Android 录音MediaRecorder到AudioRecord
- 机器/深度学习概率论与数理统计学习笔记
- RunLoop总结:RunLoop的应用场景(四)
- SQL数据库 最基础
- 你所不知道的"网站外链"高级操作策略
- 2017.6.17 字符串输入
- 求鞍点
- JavaScript面向对象程序设计——对象