为什么std :: vector :: emplace在没有调用任何拷贝构造函数的情况下调用析构函数?

时间:2016-04-29 01:34:49

标签: c++ c++11 destructor stdvector

我将对象存储在std::vector中,我希望尽可能避免调用析构函数。
我用移动的方法替换了复制构造函数和赋值:

class Object
{
    Object(const Object&) = delete;
    Object(Object&&);
    Object& operator=(const Object&) = delete;
    Object& operator=(Object&&);
    [...]
};

我正在初始化它:

std::vector<Object>   container;

container.reserve(42) // Reserve a lot in order to be sure it won't be a problem

然后,我用emplace_back添加两个元素(构造函数接受一个int参数):

container.emplace_back(1);
container.emplace_back(3);

直到那里,一切都很好。但后来我想在最后一个元素emplace之前插入一个元素:

auto it = container.end();

it--; // Last position.
it--; // Before last position.
container.emplace(it, 2);

但这里有一个析构函数。

我试图找到Valgrind的原因,它显示emplace函数调用_M_insert_aux来调用我的析构函数。

我怎么能避免这种情况?

1 个答案:

答案 0 :(得分:2)

你无法避免这种情况。这就是vector的工作原理。它是一个连续的数组。将新元素插入连续数组的唯一方法是向下移动旧元素。这意味着使用移动分配将它们移动到新的位置。

因此,如果您有以下向量及其内容:

[5][12][16]

如果你在第二个元素之后插入,那么在某些时候你有这个:

[5][12][*][16]

哪里&#34; *&#34;是移动元素的值。

然后是emplaceemplace明确地将构建值;这是它的用途。但是,第3个元素中已经存在一个活动对象:移动的值。

因此,在可以在其位置构造新对象之前,必须销毁。因此必须调用析构函数。

如果您使用insert而不是emplace,那么您仍然会调用析构函数。但那将是您传递给insert函数的对象的析构函数。

所以有一个&#34;额外&#34;析构函数叫某处

但实际上,你不应该担心析构函数的数量。专注于绝对成本。一般来说,如果你有一个只移动类型,那么移动值的析构函数会很便宜。