0%

C++ push_back和emplace_back的区别

push_back()向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素)。

emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

事实上,大多数情况下二者没有区别,只有在少数情况下 emplace_back() 效率更高。主要是 emplace_back() 支持 in-place construction

直接看下代码:

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
60
61
class TestClass
{
int a_;
std::string b_;

public:
TestClass(const int &a, const std::string &b) : a_(a), b_(b)
{
std::cout << "default constructor" << std::endl;
};
TestClass(const TestClass &other) : a_(other.a_), b_(other.b_)
{
std::cout << "copy constructor" << std::endl;
}
TestClass(TestClass &&other) : a_(other.a_), b_(std::move(other.b_))
{
std::cout << "move constructor" << std::endl;
}
~TestClass() { std::cout << "destructor" << std::endl; }
};

int main(int argc, char **argv)
{
std::vector<TestClass> vec;
vec.reserve(100);

TestClass t1(1, "1");
TestClass t2(2, "2");

std::cout << "\n-----------------0---------------\n";

vec.push_back(t1);
vec.clear();
std::cout << "\n";
vec.emplace_back(t1);
vec.clear();
std::cout << "-----------------1---------------\n";

vec.push_back(std::move(t1));
vec.clear();
std::cout << "\n";
vec.push_back(std::move(t2));
vec.clear();
std::cout << "----------------2----------------\n";

vec.push_back(TestClass(3, "3"));
vec.clear();
std::cout << "\n";
vec.emplace_back(TestClass(3, "3"));
vec.clear();
std::cout << "----------------3----------------\n";

vec.push_back({4, "4"});
vec.clear();
std::cout << "\n";
vec.emplace_back(4, "4"); // in-place construction
vec.clear();
std::cout << "----------------4----------------\n";

return 0;
}

输出:

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
default constructor
default constructor

-----------------0---------------
copy constructor
destructor

copy constructor
destructor
-----------------1---------------
move constructor
destructor

move constructor
destructor
----------------2----------------
default constructor
move constructor
destructor
destructor

default constructor
move constructor
destructor
destructor
----------------3----------------
default constructor
move constructor
destructor
destructor

default constructor
destructor
----------------4----------------

destructor
destructor

从结果来看,只有直接调用构造有区别

1
2
vec.push_back({4, "4"});
vec.emplace_back(4, "4");

在这种情况下,push_back() 会调用默认构造和移动构造,对应两次析构;而 emplace_back() 只调用一次默认构造一次析构, 效率更高。