1. 6个函数代码及详细注释
在线代码链接跳转
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <span>
using namespace std;
using ID=unsigned int;
class Test {
public:
static ID genId;
int mdata;
//1. 默认构造函数: 当对象被创建而没有提供任何参数时调用。
Test() : mid(++genId), mdata(0) {
std::cout << "Default constructor called, mid = " << mid << std::endl;
}
//2. 析构函数: 当对象的生命周期结束时调用,例如对象离开其作用域或被 delete。
virtual ~Test() {
std::cout << "Destructor called, mid = " << mid << std::endl;
}
//3. 拷贝构造函数: 当一个对象以值的方式传递给函数或从函数返回,或者用一个同类型的其他对象初始化一个新对象时调用。
Test(const Test& other) : mdata(other.mdata) {
mid = ++genId;
std::cout << "Copy constructor called, mid = " << mid << std::endl;
}
//4. 拷贝赋值运算符: 当一个对象被用来给另一个同类型的已存在对象赋值时调用。
Test& operator=(const Test& other) {
this->mdata = other.mdata;
mid = ++genId;
std::cout << "Copy assignment operator called, mid = " << mid << std::endl;
return *this;
}
//5. 移动构造函数: 当一个对象被用来初始化另一个对象,且源对象可作为右值引用时调用。
Test(Test&& other) : mid(++genId), mdata(other.mdata) {
//other.mid = -1; // 理论上即将消失的对象的数据应该被clear, 但是这里为了追踪obj 生命周期就没有修改
other.mdata = -1; // 理论上即将消失的对象(右值)的数据应该被clear
std::cout << "Move constructor called, mid = " << mid << std::endl;
}
//6. 移动赋值运算符: 当一个对象被用来给另一个同类型的已存在对象赋值,且源对象可作为右值引用时调用
Test& operator=(Test&& other) {
if (this != &other) {
mid = ++genId;
//other.mid = -1; // 理论上即将消失的对象的数据应该被clear, 但是这里为了追踪obj 生命周期就没有修改
other.mdata = -1; // 理论上即将消失的对象(右值)的数据应该被clear
std::cout << "Move assignment operator called, mid = " << mid << std::endl;
}
return *this;
}
private:
ID mid;
};
Test process_1(Test t) {
cout<<"process_1 +"<<endl;
Test tmp;
cout<<"process_1 -"<<endl;
return tmp;
}
Test process_2(Test& t) {
cout<<"process_2 +"<<endl;
Test tmp;
cout<<"process_2 -"<<endl;
return tmp;
}
Test process_3(Test&& t) {
cout<<"process_3 +"<<endl;
Test tmp;
cout<<"process_3 -"<<endl;
return tmp;
}
Test process_4(Test&& t) {
cout<<"process_4 +"<<endl;
Test tmp;
cout<<"process_4 -"<<endl;
return {tmp};
}
ID Test::genId = 0;
int main() {
//1. 调用默认构造函数
cout<<"== 1. 调用默认构造函数 =="<<endl;
{
Test p1; // 调用默认构造函数
Test* p2 = new Test;
Test* p3 = new Test();
Test* p4(new Test);
Test* p5{new Test()};
shared_ptr<Test> p6{new Test, [](auto p) {
cout<<"deleter called +"<<endl;
delete p;
cout<<"deleter called -"<<endl;
}};
shared_ptr<Test> p7 = make_shared<Test>();
delete p2; // 调用析构函数
delete p3;
delete p4;
delete p5;
cout<<"<Leaving scope {} soon>"<<endl;
}
cout<<"== 1. 调用默认构造函数 =="<<endl<<endl;
//3. 调用拷贝构造函数
cout<<"== 3. 调用拷贝构造函数 =="<<endl;
{
Test e1; // 调用默认构造函数
Test e2{e1}; // 拷贝构造 [ Test e2(e1); Test e2{e1}; Test e2 = {e1};
Test e3(e1); // 拷贝构造
Test e4 = e1; // 拷贝构造
Test& e7 = e1; // 特别注意:代码声明了一个指向 Test 类实例 e1 的引用 e3,并没有新的对象产生,所以不会调用任何构造函数
shared_ptr<Test> p4(new Test()); // 调用Test默认构造函数,等价写法:p4(new Test()) or p4{new Test} or p4{new Test()}
shared_ptr<Test> p5 = p4; // 等价写法: p5(p4) or p5{p4}; 此处都是调用shared_ptr的拷贝构造函数
cout<< "$$ 数组测试 (1) $$"<<endl;
Test e5[3] = {e1,e1,e1}; // 拷贝构造 分别调用三次
Test e6[3] {e1,e1,e1}; // 拷贝构造 分别调用三次
cout<< "$$ 数组测试 (2) $$"<<endl;
vector<Test> vec1= {e1,e1};
vector<Test> vec2 {e1,e1};
cout<< "$$ 数组测试 (3) $$"<<endl;
span<Test> s1(begin(vec1),end(vec2));
cout<< "$$ 数组测试 (4) $$"<<endl;
cout<<"## 函数相关测试 ##"<<endl;
cout<<"begin process_1(值传递)"<<endl;
Test ret1 = process_1(e1);
cout<<"begin process_2(引用传递)"<<endl;
Test ret2 = process_2(e1);
cout<<"begin process_3(右值引用传递)"<<endl;
Test ret3 = process_3(std::move(e1));
cout<<"begin process_4(右值引用传递 + return {tmp};)"<<endl;
Test ret4 = process_4(std::move(e1)); // 注意:函数内部 "return {tmp};" 返回会多执行一次拷贝构造函数
cout<<"## 函数相关测试 ##"<<endl;
cout<<"<Leaving scope {} soon>"<<endl;
}
cout<<"== 3. 调用拷贝构造函数 =="<<endl<<endl;
cout<<"== 4. 拷贝赋值运算符 =="<<endl;
{
Test a;
Test b;
b = a; // 调用拷贝赋值运算符
cout<<"<Leaving scope {} soon>"<<endl;
}
cout<<"== 4. 拷贝赋值运算符 =="<<endl<<endl;
cout<<"== 5. 移动构造函数 =="<<endl;
{
Test a;
Test b = std::move(a); // 调用移动构造函数
cout<<"<Leaving scope {} soon>"<<endl;
}
cout<<"== 5. 移动构造函数 =="<<endl<<endl;
cout<<"== 6. 移动赋值运算符 =="<<endl;
{
Test a;
Test b;
b = std::move(a); // 调用移动赋值运算符 operator=(Test&&)
cout<<"<Leaving scope {} soon>"<<endl;
}
cout<<"== 6. 移动赋值运算符 =="<<endl<<endl;
return 0;
}
2. 代码的执行结果
== 1. 调用默认构造函数 ==
Default constructor called, mid = 1
Default constructor called, mid = 2
Default constructor called, mid = 3
Default constructor called, mid = 4
Default constructor called, mid = 5
Default constructor called, mid = 6
Default constructor called, mid = 7
Destructor called, mid = 2
Destructor called, mid = 3
Destructor called, mid = 4
Destructor called, mid = 5
<Leaving scope {} soon>
Destructor called, mid = 7
deleter called +
Destructor called, mid = 6
deleter called -
Destructor called, mid = 1
== 1. 调用默认构造函数 ==
== 3. 调用拷贝构造函数 ==
Default constructor called, mid = 8
Copy constructor called, mid = 9
Copy constructor called, mid = 10
Copy constructor called, mid = 11
Default constructor called, mid = 12
$$ 数组测试 (1) $$
Copy constructor called, mid = 13
Copy constructor called, mid = 14
Copy constructor called, mid = 15
Copy constructor called, mid = 16
Copy constructor called, mid = 17
Copy constructor called, mid = 18
$$ 数组测试 (2) $$
Copy constructor called, mid = 19
Copy constructor called, mid = 20
Copy constructor called, mid = 21
Copy constructor called, mid = 22
Destructor called, mid = 20
Destructor called, mid = 19
Copy constructor called, mid = 23
Copy constructor called, mid = 24
Copy constructor called, mid = 25
Copy constructor called, mid = 26
Destructor called, mid = 24
Destructor called, mid = 23
$$ 数组测试 (3) $$
$$ 数组测试 (4) $$
## 函数相关测试 ##
begin process_1(值传递)
Copy constructor called, mid = 27
process_1 +
Default constructor called, mid = 28
process_1 -
Destructor called, mid = 27
begin process_2(引用传递)
process_2 +
Default constructor called, mid = 29
process_2 -
begin process_3(右值引用传递)
process_3 +
Default constructor called, mid = 30
process_3 -
begin process_4(右值引用传递 + return {tmp};)
process_4 +
Default constructor called, mid = 31
process_4 -
Copy constructor called, mid = 32
Destructor called, mid = 31
## 函数相关测试 ##
<Leaving scope {} soon>
Destructor called, mid = 32
Destructor called, mid = 30
Destructor called, mid = 29
Destructor called, mid = 28
Destructor called, mid = 25
Destructor called, mid = 26
Destructor called, mid = 21
Destructor called, mid = 22
Destructor called, mid = 18
Destructor called, mid = 17
Destructor called, mid = 16
Destructor called, mid = 15
Destructor called, mid = 14
Destructor called, mid = 13
Destructor called, mid = 12
Destructor called, mid = 11
Destructor called, mid = 10
Destructor called, mid = 9
Destructor called, mid = 8
== 3. 调用拷贝构造函数 ==
== 4. 拷贝赋值运算符 ==
Default constructor called, mid = 33
Default constructor called, mid = 34
Copy assignment operator called, mid = 35
<Leaving scope {} soon>
Destructor called, mid = 35
Destructor called, mid = 33
== 4. 拷贝赋值运算符 ==
== 5. 移动构造函数 ==
Default constructor called, mid = 36
Move constructor called, mid = 37
<Leaving scope {} soon>
Destructor called, mid = 37
Destructor called, mid = 36
== 5. 移动构造函数 ==
== 6. 移动赋值运算符 ==
Default constructor called, mid = 38
Default constructor called, mid = 39
Move assignment operator called, mid = 40
<Leaving scope {} soon>
Destructor called, mid = 40
Destructor called, mid = 38
== 6. 移动赋值运算符 ==