C++ 何时调用默认构造、拷贝构造、移动构造、拷贝赋值、移动赋值、析构以及对象析构顺序
一小段代码足以说明问题
核心测试代码
int main()
{
cout << "1."; Foo a1; // 默认构造
cout << "2."; Foo a2(a1); // 拷贝构造(直接初始化)
cout << "3."; Foo a3 = a1; // 拷贝构造(拷贝初始化)
cout << "4."; Foo a4 = static_cast<Foo>(10); // 默认优化:直接构造;如果禁用一切优化,直接构造+移动构造(拷贝初始化)
cout << "5."; a1 = a2; // 拷贝赋值
cout << "6."; a1 = static_cast<Foo>(5); // 直接构造、移动赋值、立即析构右侧移动后的对象
cout << "----------" << endl;
}
执行结果及分析
# g++ main.cpp && ./a.out
1.默认构造 ptr = 0 # a1
2.拷贝构造 ptr = 0x559e05fe0280 # a2
3.拷贝构造 ptr = 0x559e05fe02a0 # a3
4.直接构造 ptr = 0x559e05fe02c0 # a4
5.拷贝赋值 ptr = 0x559e05fe02f0 # a1=a2,深拷贝 a2 导致生成新的 ptr 地址
6.直接构造 ptr = 0x559e05fe0310 # static_cast<Foo>(5)
移动赋值 ptr = 0x559e05fe0310 # static_cast<Foo>(5) 转移给了 a1
析构 ptr = 0 # 转移后 static_cast<Foo>(5) 的析构
----------
析构 ptr = 0x559e05fe02c0 # a4
析构 ptr = 0x559e05fe02a0 # a3
析构 ptr = 0x559e05fe0280 # a2
析构 ptr = 0x559e05fe0310 # a1
结论
- 直接初始化和拷贝初始化都调用拷贝构造
- 右值(将亡值)如测试代码中的
static_cast<Foo>(5)
,立即析构 - 局部变量析构顺序(a4,a3,a2,a1)和定义顺序(a1,a2,a3,a4)相反
- 默认优化,可以跳过构造+移动,省略临时变量,直接构造 a4 对象。即
Foo a4 = static_cast<Foo>(10);
默认直接优化为Foo a4(10);
。通过 cppInsight 也能得到相同结论:默认情况下,string s1(3, 't');
和string s2 = string(3,'t');
生成的代码完全相同 https://cppinsights.io/s/161fe366
完整测试代码
#include <iostream>
using namespace std;
class Foo {
public:
Foo() : size(0), ptr(nullptr) { cout << "默认构造 ptr = " << ptr << endl; }
explicit Foo(unsigned s) : size(s)
{
ptr = new int[size];
cout << "直接构造 ptr = " << ptr << endl;
}
Foo(const Foo &I) : size(I.size)
{
ptr = new int[size];
for (unsigned i = 0; i < size; ++i) ptr[i] = I.ptr[i];
cout << "拷贝构造 ptr = " << ptr << endl;
}
Foo(Foo &&I) : size(I.size)
{
ptr = I.ptr;
I.ptr = nullptr;
cout << "移动构造 ptr = " << ptr << endl;
}
Foo &operator=(const Foo &I)
{ // 内存泄漏!标准解法:拷贝、交换
if (this == &I) return *this;
size = I.size;
ptr = new int[size];
for (unsigned i = 0; i < size; ++i) ptr[i] = I.ptr[i];
cout << "拷贝赋值 ptr = " << ptr << endl;
return *this;
}
Foo &operator=(Foo &&I)
{
if (this == &I) return *this;
size = I.size;
ptr = I.ptr;
I.ptr = nullptr;
cout << "移动赋值 ptr = " << ptr << endl;
return *this;
}
~Foo()
{
cout << "析构 ptr = " << ptr << endl;
if (ptr) {
delete[] ptr;
ptr = nullptr;
}
}
private:
unsigned size;
int *ptr;
};
int main()
{
cout << "1."; Foo a1; // 默认构造
cout << "2."; Foo a2(a1); // 拷贝构造(直接初始化)
cout << "3."; Foo a3 = a1; // 拷贝构造(拷贝初始化)
cout << "4."; Foo a4 = static_cast<Foo>(10); // 默认优化:直接构造;如果禁用一切优化,直接构造+移动构造(拷贝初始化)
cout << "5."; a1 = a2; // 拷贝赋值
cout << "6."; a1 = static_cast<Foo>(5); // 直接构造、移动赋值、立即析构右侧移动后的对象
cout << "----------" << endl;
}
本文作者:Zijian/TENG(微信公众号:好记性如烂笔头),转载请注明原文链接:https://www.cnblogs.com/tengzijian/p/16187388.html