cpp不同种类构造函数

cpp 的构造函数种类

  1. 构造函数:生成一个新的对象。
  2. 拷贝构造函数:参数是 const T& x,用于拷贝。
  3. 赋值构造函数:这个严格意义来说不是构造函数,是赋值运算符 = 的重载。初始化的时候不会调用这个函数!
  4. 移动构造函数:参数是 T &&x,用于移动构造,提升效率。

代码示例

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <string>

using namespace std;

class Integer {
private:
int* m_ptr;
public:
// 普通构造函数
Integer(int value) : m_ptr(new int(value)) {
cout << "constructor" << endl;
}
// 拷贝构造函数
Integer(const Integer& source) : m_ptr(new int(*source.m_ptr)) {
cout << "copy constructor" << endl;
}
// 移动构造函数
Integer(Integer&& source) : m_ptr(source.m_ptr) {
source.m_ptr = nullptr;
cout << "move constructor" << endl;
}
// 赋值运算符重载
Integer& operator=(const Integer& source) {
m_ptr = new int(*source.m_ptr);
cout << "copy assignment constructor" << endl;
return *this;
}
~Integer() {
cout << "destructor:" << GetValue() << endl;
delete m_ptr;
}
int GetValue(void) {
if (m_ptr) {
return *m_ptr;
} else {
return -1;
}
}
};

Integer getNum() {
Integer a(100);
return a;
}
int main(int argc, char const* argv[]) {
Integer a(getNum());
cout << "a=" << a.GetValue() << endl;
cout << "-----------------" << endl;
Integer temp(10000);
Integer b(temp);
cout << "b=" << b.GetValue() << endl;
cout << "-----------------" << endl;
Integer c = b;
c = a;
cout << "c=" << c.GetValue() << endl;
cout << "-----------------" << endl;
return 0;
}

在编译的时候一定要指定编译选项 --no-elide-constructors,否则会被编译器优化!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@└────> # ./a.out 
constructor
move constructor
destructor:-1
move constructor
destructor:-1
a=100
-----------------
constructor
copy constructor
b=10000
-----------------
copy constructor
copy assignment constructor
c=100
-----------------
destructor:100
destructor:10000
destructor:10000
destructor:100

分析

a

  1. 第一个 constructor,是在 getNum() 中首句 Integer a(100) 所打印的,调用默认的构造函数。
  2. 第二个 move constructor 是因为 return a 的时候,这个 a 是个右值,作为 main 函数 getNum() 的返回值,而调用的移动构造函数,将 getNum() 函数内的返回值移动构造给 main 函数接收 getNum() 的对象。
  3. 第三个 destructor 是析构 getNum() 中的对象 a。
  4. 第四个 move constructor 是因为 Integer a(右值),所以调用移动构造函数。
  5. 第五个 destructor 是析构 Integer a(右值) 中的右值而显示的。

b

  1. 第一个 constructor 是 Integer temp(10000); 调用的默认构造函数。
  2. 第二个 copy constructor 是 Integer b(temp); 调用的拷贝构造函数,将 temp 拷贝给 b;

c

  1. 第一个 copy constructor 是 Integer c = b; 调用的拷贝构造函数,可以看到此处并没有调用拷贝赋值运算符,因为这是在初始化!
  2. 第二个 copy assignment constructor 是 c = a 调用的才是拷贝赋值运算符。

可以看到,初始化的时候不会调用 拷贝赋值运算符!!!

析构

最后的四个 destructor 是析构。根据规则,先构造的后析构,后调用的先析构。析构顺序:c = 100,b = 10000,temp = 10000,a = 100。