目录

关于 C++ STL vector 中的 push_back 和 emplace_back,reserve 和 resize

push_back 和 emplace_back

在 vector 尾部插入元素有两种方法:push_back()emplace_back()

函数原型

void push_back (const value_type& val);void push_back (value_type&& val); template <class... Args> void emplace_back (Args&&... args);

调用 push_back 的过程

  1. 将调用构造函数来创建临时对象。
  2. 将在容器的内存中构造临时对象的副本。请注意,move constructor如果存在,则将调用 ,因为临时对象是 一个 rvalue,否则copy constructor应调用 。
  3. 复制后会调用析构函数来销毁临时对象。

区别

  • 对于 push_back ,他会先创建一个新元素,然后再拷贝或者移动到 vector 中。
  • 对于 emplace_back,使用完美转发将参数直接发送到构造函数以就地创建对象。

例子

下面这个例子演示了,emplace_back() 函数可以减少一次拷贝或移动构造的过程,也就是在参数输入时,不用写xxx()

 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
#include <vector>
#include <cassert>
#include <iostream>
#include <string>
 
struct President
{
    std::string name;
    std::string country;
    int year;
 
    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
 
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
 
    President& operator=(const President& other) = default;
};
 
int main()
{
    std::vector<President> elections;
    std::cout << "emplace_back:\n";
    auto& ref = elections.emplace_back("Nelson Mandela", "South Africa", 1994);
    assert(ref.year == 1994 && "uses a reference to the created object (C++17)");
 
    std::vector<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
 
    std::cout << "\nContents:\n";
    for (President const& president: elections)
        std::cout << president.name << " was elected president of "
                  << president.country << " in " << president.year << ".\n";
 
    for (President const& president: reElections)
        std::cout << president.name << " was re-elected president of "
                  << president.country << " in " << president.year << ".\n";
}

输出:

emplace_back:
I am being constructed.
 
push_back:
I am being constructed.
I am being moved.
 
Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.

push_back() 在内部似乎也会调用 emplace_back()?

关于 reserve 和 resize

reserve (不够时,更改 capacity 大小)

要求 vector 容量至少足以包含n 个元素。

如果n大于当前 vector 的容量,该函数会导致容器重新分配其存储空间,将其容量增加到n(或更大)。

在所有其他情况下,函数调用不会导致重新分配,并且 vector 容量不受影响。此函数对 vector 大小没有影响,也不能改变其元素。

resize (删除时,更改 size 大小;增加时,更改 size 大小,capacity 不够则更改)

调整 vector 的大小,使其包含n 个元素。

如果n小于当前 vector 大小,则内容将减少到前n 个元素,删除超出的元素(并销毁它们)。

如果n大于当前 vector 大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。如果指定了val,则新元素将被初始化为val的副本,否则,它们将被值初始化。

如果n也大于当前 vector 容量,会自动重新分配已分配的存储空间。

请注意,此函数通过插入或删除 vector 中的元素来更改 vector 的实际内容。