C++

vector的push_back与emplace_back

Posted by DEVIN on Mon, Jul 17, 2023

push_back与emplace_back

 1#include <iostream>
 2#include <vector>
 3using namespace std;
 4
 5class A {
 6public:
 7    A() = default;
 8    A(string name) : _name(name) { cout << "ctor: " << _name << endl; }
 9    ~A() { cout << "dtor: " << _name << endl; }
10    // 拷贝构造函数
11    A(const A &other) { _name += "cp-" + other._name; cout << "cp-ctor: " << _name << endl; }
12    // 赋值运算符
13    A& operator=(const A &other) {
14        if (this != &other) {
15            _name += "cp-" + other._name;
16            cout << "cp-op: " << _name << endl;
17        }
18        return *this;
19    }
20    // 移动构造函数
21    A(A &&other) noexcept { _name += "mv-" + other._name; cout << "mv-ctor: " << _name << endl; }
22    // 移动赋值运算符
23    A& operator=(A &&other) noexcept {
24        if (this != &other) {
25            _name += "mv-" + other._name;
26            cout << "mv-op: " << _name << endl;
27        }
28        return *this;
29    }
30
31    string _name;
32};
33
34int main()
35{
36    vector<A> arr;
37    arr.reserve(100); // 重要!重新分配内存时可能导致测试结果有迷惑性
38
39    printf("==== push_back(\"a1\") ====\n");
40    arr.push_back(string("a1"));
41    printf("\n==== emplace_back(\"a2\") ====\n");
42    arr.emplace_back(string("a2"));
43
44    printf("\n==== push_back/emplace_back(lvalue) ====\n");
45    A a3("a3");
46    arr.push_back(a3);
47    arr.emplace_back(a3);
48
49    printf("\n==== push_back/emplace_back(rvalue) ====\n");
50    A a4("a4");
51    arr.push_back(std::move(a4));
52    A a5("a5");
53    arr.emplace_back(std::move(a5));
54
55    printf("\n==== return ====\n");
56    return 0;
57}

输出为:

 1==== push_back("a1") ====
 2ctor: a1
 3mv-ctor: mv-a1
 4dtor: a1
 5
 6==== emplace_back("a2") ====
 7ctor: a2
 8
 9==== push_back/emplace_back(lvalue) ====
10ctor: a3
11cp-ctor: cp-a3
12cp-ctor: cp-a3
13
14==== push_back/emplace_back(rvalue) ====
15ctor: a4
16mv-ctor: mv-a4
17ctor: a5
18mv-ctor: mv-a5
19
20==== return ====
21dtor: a5
22dtor: a4
23dtor: a3
24dtor: mv-a1
25dtor: a2
26dtor: cp-a3
27dtor: cp-a3
28dtor: mv-a4
29dtor: mv-a5

移动构造函数用noexcept修饰后,vector扩容时才会调用

为什么需要将移动构造函数和移动赋值运算符标记为noexcept

 1#include <iostream>
 2#include <vector>
 3using namespace std;
 4
 5class A {
 6public:
 7    A() = default;
 8    A(string name) : _name(name) { cout << "ctor: " << _name << endl; }
 9    ~A() { cout << "dtor: " << _name << endl; }
10    // 拷贝构造函数
11    A(const A &other) { _name = "cp-" + other._name; cout << "cp-ctor: " << _name << endl; }
12    // 赋值运算符
13    A& operator=(const A &other) {
14        if (this != &other) {
15            _name = "cp-" + other._name;
16            cout << "cp-op: " << _name << endl;
17        }
18        return *this;
19    }
20    // 移动构造函数
21    A(A &&other) noexcept { _name = "mv-" + other._name; cout << "mv-ctor: " << _name << endl; }
22    // 移动赋值运算符
23    A& operator=(A &&other) noexcept {
24        if (this != &other) {
25            _name = "mv-" + other._name;
26            cout << "mv-op: " << _name << endl;
27        }
28        return *this;
29    }
30
31    string _name = "anonymous";
32};
33
34int main() {
35    vector<A> arr(4);
36    arr.reserve(4);
37    cout << "capacity: " << arr.capacity() << endl; // 4
38
39    A a1("a1");
40    A a2("a2");
41    arr.push_back(a1); // 触发vector内存的重新分配: 第5个元素调用cp-ctor
42                       // 如果mv-ctor声明为noexcept,则前4个元素调用移动构造函数; 否则调用拷贝构造函数cp-ctor
43    arr.push_back(std::move(a2)); // 第6个元素调用mv-ctor
44    cout << "capacity: " << arr.capacity() << endl; // 8
45
46    cout << "==== return ====" << endl;
47}

输出信息为:

 1capacity: 4
 2ctor: a1
 3ctor: a2
 4cp-ctor: cp-a1
 5mv-ctor: mv-anonymous
 6dtor: anonymous
 7mv-ctor: mv-anonymous
 8dtor: anonymous
 9mv-ctor: mv-anonymous
10dtor: anonymous
11mv-ctor: mv-anonymous
12dtor: anonymous
13mv-ctor: mv-a2
14capacity: 8
15==== return ====
16dtor: a2
17dtor: a1
18dtor: mv-anonymous
19dtor: mv-anonymous
20dtor: mv-anonymous
21dtor: mv-anonymous
22dtor: cp-a1
23dtor: mv-a2