emplace_back() 的行为与预期不符。

25
我写了一个简单的程序来测试在标准库容器内创建对象的in-place方法。这是我的代码:
#include <vector>
#include <iostream>

class AB
{
public:
   explicit AB(int n);
   AB(const AB& other) = delete;
   AB(AB&& other);
   AB& operator=(const AB& other) = delete;
   AB& operator=(AB&& other) = default;
private:
   int i;
};

AB::AB(int n): i( n )
{
   std::cout << "Object created." << std::endl;
};

AB::AB(AB&& other): i( std::move(other.i) )
{
   std::cout << "Object moved." << std::endl;
};

int main()
{
   std::vector< AB > v;
   v.emplace_back(1);
   v.emplace_back(2);
   v.emplace_back(3);
};

我使用g ++(版本4.8.2)进行编译。运行输出后,我得到了:

Object created.
Object created.
Object moved.
Object created.
Object moved.
Object moved.

但我预料到会发生这样的事情:

Object created.
Object created.
Object created.

我认为放置的整个目的是为了摆脱移动构造函数调用。AB类中是否有未满足的任何要求?

感谢您的帮助。


5
很高兴看到有一个清晰明确的问题,包含了所有必要信息和一个自足的可工作代码示例。不幸的是,这种情况现在已经成为了例外。 - juanchopanza
5
注意:如果您不删除复制构造函数,那么您的对象将会被复制。这是因为除非移动构造函数被标记为noexcept,否则在重新分配元素时,vector将倾向于使用非破坏性的复制构造函数。因此,请确保标记移动构造函数为noexcept :) - Matthieu M.
2个回答

32
问题在于向量在添加更多元素时被重新调整大小,导致额外的移动。如果您在开始时预留了足够的容量,就会得到预期的结果:

问题在于你添加更多元素时,向量的大小会被重新调整,导致额外的移动。如果在开始时预留了足够的容量,就能获得预期的结果:

   std::vector< AB > v;
   v.reserve(3);
   v.emplace_back(1);
   v.emplace_back(2);
   v.emplace_back(3);

提供

Object created.
Object created.
Object created.

在gcc 4.8.2上。请注意您可以通过查看v.capacity()来跟踪原始代码中向量的增长。


1
感谢您的回答。对于我的理解非常有帮助。 - WielandK

2

放置的目的是为了消除COPY构造函数调用。当向量已满时,它可能会移动对象以调整大小。移动对象是可以接受的,但复制对象很昂贵。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接