cpp 的构造函数种类
- 构造函数:生成一个新的对象。
- 拷贝构造函数:参数是 const T& x,用于拷贝。
- 赋值构造函数:这个严格意义来说不是构造函数,是赋值运算符 = 的重载。初始化的时候不会调用这个函数!
- 移动构造函数:参数是 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
- 第一个 constructor,是在 getNum() 中首句 Integer a(100) 所打印的,调用默认的构造函数。
- 第二个 move constructor 是因为 return a 的时候,这个 a 是个右值,作为 main 函数 getNum() 的返回值,而调用的移动构造函数,将 getNum() 函数内的返回值移动构造给 main 函数接收 getNum() 的对象。
- 第三个 destructor 是析构 getNum() 中的对象 a。
- 第四个 move constructor 是因为 Integer a(右值),所以调用移动构造函数。
- 第五个 destructor 是析构 Integer a(右值) 中的右值而显示的。
b
- 第一个 constructor 是 Integer temp(10000); 调用的默认构造函数。
- 第二个 copy constructor 是 Integer b(temp); 调用的拷贝构造函数,将 temp 拷贝给 b;
c
- 第一个 copy constructor 是 Integer c = b; 调用的拷贝构造函数,可以看到此处并没有调用拷贝赋值运算符,因为这是在初始化!
- 第二个 copy assignment constructor 是 c = a 调用的才是拷贝赋值运算符。
可以看到,初始化的时候不会调用 拷贝赋值运算符!!!
析构
最后的四个 destructor 是析构。根据规则,先构造的后析构,后调用的先析构。析构顺序:c = 100,b = 10000,temp = 10000,a = 100。