C++ Note 3
本文是我的C++笔记的第三篇 My Thrid C++ Note;
explict
防止类的构造函数的隐式转换
1class A
2{
3private:
4 int x;
5public:
6 A(int x_): x{x_} {}
7};
8
9// ...
10
11A a = 3; // YES
12A a2{3}; // YES
这样是对的
1class A
2{
3private:
4 int x;
5public:
6 explict A(int x_): x{x_} {}
7};
8
9// ...
10
11A a = 3; // NO
12A a{3}; //YES
析构函数 移动构造 和 emplace_back
下列代码
1class A
2{
3private:
4 int x;
5
6public:
7 A(int xx) : x{xx} {}
8 A() : A(0) {}
9 ~A() { cout << "goodbye " << x << endl; }
10};
11
12int main()
13{
14 vector<A> v;
15 v.emplace_back(A{0});
16 v.emplace_back(A{1});
17 v.emplace_back(A{2});
18 cout << "--------------------------------------\n";
19
20 // OUTPUT
21 // goodbye 0
22 // goodbye 0
23 // goodbye 1
24 // goodbye 0
25 // goodbye 1
26 // goodbye 2
27 // --------------------------------------
28 // goodbye 0
29 // goodbye 1
30 // goodbye 2
31}
其原因在于:
首先:emplace_back
只有在传入构造参数列表的时候和push_back
有区别。其他的时候没有区别。
这里相当于先生成临时对象A{0}
,再拷贝构造到v中。从而执行了一次对于0的析构
之后,因为要再加入A{1}
,而目前的v的可用空间大小是1
因此需要再向系统申请一块大小为2的空间。之后再把原来的A{0}
复制过去。再放弃原来的大小为1的地址上的A{0}
,因此又执行一次对于0的析构。之后构造临时对象A1,再复制到v中。则临时对象析构,造成一次对于1的析构。
之后要加入2. 方法一样。先开辟新内存空间,把原来的对象复制过去。再加入2 即可
最终,3个对象的生命周期均到达终点。则依次析构。
而
1 vector<A> v;
2 v.reserve(10);
3 v.emplace_back(A{0});
4 v.emplace_back(A{1});
5 v.emplace_back(A{2});
在提前预留了空间之后,输出为
1goodbye 0
2goodbye 1
3goodbye 2
4--------------------------------------
5goodbye 0
6goodbye 1
7goodbye 2
我们输出capacity即可看到我们的猜测是正确的。
1 vector<A> v;
2 cout << "CAPACITY " << v.capacity() << endl;
3 v.emplace_back(A{0});
4 cout << "CAPACITY " << v.capacity() << endl;
5 v.emplace_back(A{1});
6 cout << "CAPACITY " << v.capacity() << endl;
7 v.emplace_back(A{2});
8 cout << "CAPACITY " << v.capacity() << endl;
9 cout << "--------------------------------------\n";
得到
1CAPACITY 0
2goodbye 0
3CAPACITY 1
4goodbye 0
5goodbye 1
6CAPACITY 2
7goodbye 0
8goodbye 1
9goodbye 2
10CAPACITY 4
11--------------------------------------
12goodbye 0
13goodbye 1
14goodbye 2
结论: emplace_back以参数列表的形式传入时,不论是否有移动构造函数,都是原地构造,只会调用一次构造函数(只有这一项和push_back有区别,其它都是一样的)
emplace_back以左值对象的形式传入时,不论是否有移动构造函数,都是调用一次拷贝构造函数
emplace_back以右值对象(例如move(左值对象),或者就是右值)的形式传入时 a. 有移动构造函数,调用一次移动构造 b. 没有移动构造函数,调用拷贝构造函数
emplace_back以 Person(“aaa”, “shandong”, 1991) 形式传入时 a. 有移动构造函数,构造临时文件 —> 移动构造 —> 临时文件析构 b. 没有移动构造函数,构造临时文件 —> 拷贝构造 —> 临时文件析构