我应该在这种情况下使用智能指针吗?

时间:2017-09-04 05:02:49

标签: c++ pointers smart-pointers raii

我知道首选规则是始终使用shared_ptr s或其他智能指针。但是,如果没有std::make_shared的副本,我不确定如何实现它。我将详细说明:

问题

我想创建一个类似树的表达式,如:

struct foo{
    std::vector<foo*> v;
};

这允许我执行以下操作:

foo add(foo& f1, foo& f2){
    return foo {&f1, &f2};
}

这很好,因为那时两人将成为新节点的孩子。

我希望正确评估以下内容:

foo x, y;
auto z = add(x,y);
assert(z.v[0] == &x && z.v[1] == &y);

这样,没有复制,这一切都很好。但是,我们在这里遇到了资源管理问题。

解决资源管理问题

如果这些元素在堆上分配,并且有人在不知不觉中,那么我们就会遇到内存泄漏。因此,最好的方法是使用智能指针进行RAII:

struct foo{
    std::vector<std::shared_ptr<foo> > v;
};

foo add(foo& f1, foo& f2){
    return foo {std::make_shared<foo>(f1), std::make_shared<foo>(f2)};
}

这很好,但我们在这里调用f1和f2的副本。假设复制需要很长时间,我们不想承担这笔费用。

我们绝对不能这样做:

foo add(foo& f1, foo& f2){
    return foo {std::shared_ptr<foo>(&f1), std::shared_ptr<foo>(&f2)};
}

因为每当我们移除z中的z = x+y时,我们都会在deletex上分别调用y,这可以在堆栈上分配。 我们绝对不希望堆叠中的delete内容。

那么在这种情况下该怎么做?

如果我应该提供有关背景的更多信息,请告诉我。

1 个答案:

答案 0 :(得分:3)

通过智能指针接受。正确应用智能指针的概念意味着您必须考虑数据的所有权语义,而不是自动调用new / delete。

您接受对非const对象的引用。这并不意味着共享,只修改对象。正如你所正确指出的那样,只要创建智能指针就会造成灾难。

add的来电者(即使只是你)必须知道他们传递的数据即将被分享。他们知道的唯一方法是他们自己是否通过智能指针。所以add更改为:

foo add(std::shared_ptr<foo> f1, std::shared_ptr<foo> f2){
    return foo{f1, f2};
}

现在,add的用户可以有效地解决这个问题。但他们很可能不会。此外,现在所述用户在调用代码时具有更大的灵活性。他们可以控制他们传递的每个对象的分配器和删除器。