在 std::vector

问题描述

我发现以下代码输出非常有趣。

class Name
{
  string _name;
public:
  Name(const string& name) : _name(name) { cout << "ctor of " << _name << endl; }
  ~Name(){ cout << "dtor of " << _name << endl; }
};
int main() {

  vector<Name> list;
  cout << "------------------START push_back" << endl;
  list.push_back(Name(string("A")));
  cout << "------------------push_back(A) performed..." << endl;
  list.push_back(Name(string("B")));
  cout << "------------------push_back(B) performed..." << endl;
  list.push_back(Name(string("C")));
  cout << "------------------push_back(C) performed..." << endl;
  cout << "------------------END push_back" << endl;

  return 0;
}

我可以理解 push_back 使用了一个额外的临时对象,这就是为什么推荐 emplace_back 以获得更好的性能。有人可以用 (???) 解释下面输出显示的额外析构函数调用吗。

------------------START push_back
ctor of A
dtor of A
------------------push_back(A) performed...
ctor of B
dtor of A(???)
dtor of B
------------------push_back(B) performed...
ctor of C
dtor of A(???)
dtor of B(???)
dtor of C
------------------push_back(C) performed...
------------------END push_back
dtor of A
dtor of B
dtor of C
------------------START emplace_back
ctor of A
------------------emplace_back(A) performed...
ctor of B
------------------emplace_back(B) performed...
ctor of C
------------------emplace_back(C) performed...
------------------END emplace_back()
dtor of A
dtor of B
dtor of C

解决方法

有人可以用 (???) 解释下面输出中显示的额外析构函数调用吗。

内存分配的大小不能改变。数组的大小相应地不能改变,因为分配给数组的内存不能改变。

向量的元素存储在分配的单个内存块中,形成一个数组。如果内存块不能改变大小,那么如何向向量添加元素?好吧,我们能做的就是分配更大的内存块,然后将元素从小块复制(移动)到大块,然后销毁旧块中的旧元素,最后释放旧块。这就是当您添加的元素超出其为其元素分配的内存块(称为容量)时,向量会执行的操作。

有人可以用 (???) 解释下面输出中显示的额外析构函数调用吗。

这些是向量重新分配时旧内存中被破坏的元素。

如果您想知道为什么在新内存中构造对象没有输出,那是因为您的类的移动构造函数没有产生输出。

如果您想知道为什么每个添加元素后都没有额外的销毁,那是因为 vector 在增长时不仅仅为单个元素分配内存。相反,它将容量乘以某个因子(通常实现使用 2 或 1.5 的因子)。当最初不知道最终元素数量时,这会为插入大量元素带来更好的渐近复杂度。

,

std::vector 是一个动态数组。

每次没有足够的内存分配来存储元素时,std::vector 会尝试重新分配更大的内存块来存储更多元素。之后,它需要将您的元素复制(移动)到其他块,隐式调用先前元素的 dtor。

要了解正在发生的事情,请尝试扩展您的课程:

class Name
{
  string _name;
public:
  Name(const string& name) : _name(name) { cout << "ctor of " << _name << endl; }
  Name(const Name& other) : _name(other._name) { cout << "copy ctor for " << _name << endl; }

  ~Name(){ cout << "dtor of " << _name << endl; }
};

现在重新运行你的程序,看看有多少复制构造函数被调用。

现在试着打电话

vector<Name> list;
list.reserve(3);
/* push_backs */

并享受:)

您可以找到更多关于向量 here 和向量成员函数保留 here