首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为什么我的对象在我将它们的unique_ptr添加到向量之后会被解构两次?

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

Stack Overflow用户
提问于 2021-01-09 18:23:13
回答 3查看 112关注 0票数 1

我试图将unique_ptr的向量生成到Example类,由于某种原因,每次调用emplace_back()时,对象都会被解构两次。我认为如果我在这里展示代码,你就更容易理解了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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);
    }
};

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

为什么会发生这种情况?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-01-09 18:41:55

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

一种选择是让向量不拥有对象。只需将原始指针存储在向量中即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::vector<Example*> ExampleList;
...
Example()
{
    ExampleList.emplace_back(this);
}

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

另一个选项是拥有一个工厂函数,该函数创建对象,将其添加到向量(然后矢量将拥有该对象),并返回指向该对象的指针。对象的生存期现在由向量来维护:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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() { ... }
};
票数 1
EN

Stack Overflow用户

发布于 2021-01-09 19:36:04

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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构造的对象相同的索引。这就是复制的意思。

票数 2
EN

Stack Overflow用户

发布于 2021-01-09 18:28:15

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 ExampleList.emplace_back(std::make_unique<Example>(*this));

如果你用纸和铅笔算出结果,你会发现Example的第二个实例就在这里被复制了。

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

因此,您真正看到的是调用原始对象和副本的析构函数。复制构造没有任何记录。

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

,我把他们的unique_ptr加到向量上?

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65649614

复制
相关文章

相似问题

添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文