emplace_back调用移动构造函数和析构函数。

8
我尝试使用emplace_back函数将两个cBar类的实例添加到一个向量中。
根据参考文献,调用emplace_back只是在向量中预留位置,然后“就地”创建新实例。
现在,我想进行一些实验:
#include <vector>
#include <iostream>
#include <memory>
#include <string>


class cBar
{
public:

    cBar(const int index);
    cBar(cBar&& other); //needed for emplace_back?
    ~cBar();

private:
    cBar(const cBar& other) = delete;
    cBar& operator=(const cBar& other) = delete;

public:
    int                         mIndex;

};




cBar::cBar(const int index) : mIndex(index)
{
    std::cout << "cBar being created ..." << std::endl;
}
cBar::cBar(cBar&& other) : mIndex(other.mIndex)
{
    std::cout << "cBar being moved ..." << std::endl;
}
cBar::~cBar()
{
    std::cout << "cBar being destroyed ..." << std::endl;
}

int main()
{
    std::vector<cBar> mBars;

    std::cout << "Begin to create 2 cBar instance, I am expecting 2 \"cBar being created ...\" messages here" << std::endl;
    mBars.emplace_back(0);//this supposed to call only cBar(const int index) constructor, and nothing more
    mBars.emplace_back(1);//this works as expected, only one constructor call

    //destroy all
    std::cout << "Destroy the 2 isntances (this works, I see the two expected \"cBar being destroyed ...\" messages here" << std::endl;
    mBars.clear();

    std::cin.get();
    return 0;
}

输出:

Begin to create 2 cBar instance, I am expecting 2 "cBar being created ..." messages here
cBar being created ...
cBar being moved ...
cBar being destroyed ...
cBar being created ...
Destroy the 2 isntances (this works, I see the two expected "cBar being destroyed ..." messages here
cBar being destroyed ...
cBar being destroyed ...

如果您运行上面的代码,您将看到第一个emplace_back在“原地”创建实例,然后立即调用移动构造函数,之后会调用析构函数。

更奇怪的是,在第二个emplace的情况下,我看到了期望的行为:只有一个构造函数调用。

我有两个问题:

  1. 如果我只想emplace_back项目,并且从未使用push_back,为什么需要在我的类中定义移动构造函数?

  2. 在第一个实例创建的情况下,为什么会调用移动构造函数,然后调用析构函数?如果我访问第一个实例的数据,所有的东西都看起来正确,所以我不知道为什么会调用移动构造函数和析构函数。

我使用Visual Studio 2015。

每一步向量尺寸的输出:

Begin to create 2 cBar instance, I am expecting 2 "cBar being created ..." messages here
Vector size:0
cBar being created ...
Vector size:1
cBar being moved ...
cBar being destroyed ...
cBar being created ...
Vector size:2
Destroy the 2 isntances (this works, I see the two expected "cBar being destroyed ..." messages here
cBar being destroyed ...
cBar being destroyed ...

3
在你的测试之前添加 mBars.reserve(9); - Kerrek SB
2个回答

10

2.在第一次创建的情况下,为什么会先调用移动构造函数然后是析构函数?

因为通过emplace_back插入第二个元素会导致重新分配;vector内部存储需要扩展,旧存储中的元素必须被复制/移动到新存储中,然后被销毁。

您可以事先使用reserve来避免重新分配。

1.如果我只想使用emplace_back添加项目,并从不使用push_back,为什么需要在我的类中定义移动构造函数?

如上所述,vector需要通过复制/移动操作来移动元素。因此,您必须为该类定义复制或移动构造函数。这对于emplace_backpush_back都是正确的,因为它们都向vector中添加元素并可能导致重新分配。


3

很有可能您的向量容量为1,在放入第二个元素时,需要重新调整向量大小。这可能会导致内存中移动大量数据,从而出现您看到的症状。

Kerreks的建议很好。 我建议在每次操作之前和之后打印向量的容量,以查看容量变化是否是原因。


希望我能同时标记两个答案。感谢您的帮助!已编辑问题并附上输出结果。 - Avi

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