为什么我的对象在我将它们的 unique_ptr 添加到向量后会被解构两次?

Why do my objects get deconstructed twice after I add their unique_ptr to a vector?

我正在尝试为 Example class 创建一个 unique_ptr 的向量,并且出于某种原因,每次我调用 emplace_back() 时,对象都会被解构两次。我认为如果我只在这里显示代码,您会更容易理解:

#include <vector>
#include <iostream>
#include <memory>

class Example;
typedef std::unique_ptr<Example> ExampleUPointer;
std::vector<ExampleUPointer> ExampleList;

class Example {
    short index;
public:
    Example()
        : index (ExampleList.size())
    {
        ExampleList.emplace_back(std::make_unique<Example>(*this));
        printf("Example %d was constructed\n", index);
    }
    ~Example() {
        printf("Example %d was deconstructed\n", index);
    }
};

然后我继续在 main() 中创建 Example class 的五个对象。这是输出:

Example 0 was constructed
Example 1 was constructed
Example 2 was constructed
Example 3 was constructed
Example 4 was constructed
Example 4 was deconstructed
Example 3 was deconstructed
Example 2 was deconstructed
Example 1 was deconstructed
Example 0 was deconstructed
Example 0 was deconstructed
Example 1 was deconstructed
Example 2 was deconstructed
Example 3 was deconstructed
Example 4 was deconstructed

为什么会这样?

 ExampleList.emplace_back(std::make_unique<Example>(*this));

如果你用纸和铅笔解决这里发生的事情,你会发现 Example 的第二个实例就在这里复制构造。

但是您的 class 有一个默认的复制构造函数,当然它不会记录任何内容。

所以,您真正看到的是原始对象和副本的析构函数都被调用了。没有记录复制构造。

添加显式复制构造函数后,您将看到正在发生的事情的全貌,该复制构造函数记录对象的哪个实例被复制构造。

I add their unique_ptr to a vector?

不,你没有那样做。您在动态范围内使用 make_unique 创建每个对象的副本(因为它就是这样做的),并将新构建的副本的 unique_ptr 添加到向量中。

A std::unique_ptr 拥有 它指向的内容。因此,对于对象的构造函数(它已经有一个所有者 - 无论正在构造对象)能够创建指向自身的有效唯一指针没有任何意义。当然,这不是你正在做的。正如 Sam 的回答所说,您正在创建一个全新的 Example 对象,一个副本,并将其添加到向量中。

一个选项是让向量不拥有对象。只需在向量中存储一个原始指针

std::vector<Example*> ExampleList;
...
Example()
{
    ExampleList.emplace_back(this);
}

这将要求您确保 Example 对象至少与向量中指向它的指针一样长。您可以让析构函数自动将其从向量中删除。

另一种选择是使用一个工厂函数来创建对象,将其添加到向量(然后向量将拥有该对象),以及 return 指向它的指针。对象的生命周期现在由向量维护:

class Example;
std::vector<std::unique_ptr<Example>> ExampleList;

class Example {
public:
    static Example *create()
    {
        // Create a new Example object and add it to the vector
        // The unique_ptr in the vector has ownership of the object
        ExampleList.push_back(std::make_unique<Example>());
        // Return a pointer to the object
        return ExampleList.back().get();
    }

private:
    // Can't call directly
    Example() { ... }
};

每次使用 int 构造函数创建对象时,该构造函数都会通过调用复制构造函数创建另一个完全不同的对象。

    Example()
      : index (ExampleList.size())
    {
      ExampleList.emplace_back(std::make_unique<Example>(*this)); //<--- here
      printf("Example %d was constructed\n", index);

就在那里。你做了第二个对象。

所以你用 int 构造函数构造了 5 个对象,用复制构造函数构造了 5 个对象,然后销毁了 10 个对象。

复制的对象与int构造的对象具有相同的索引。这就是复制的意思。