在智能指针容器中添加项目的几种方法。我想知道你会选择哪种方式。
class MyContainer
{
private:
std::vector<std::unique_ptr<Item>> mItems;
public:
bool Add(Item* item);
// This is Way 1
//
// Advantages:
// - Easy to add derived items, such as Add(new DerivedItem);
// - No interface change if smart pointer type changes to such as shared_ptr;
//
// Disadvantages:
// - Don't explicitly show the item to add must be allocated on heap;
// - If failed to add, user has to delete the item.
bool Add(std::unique_ptr<Item> item);
// This is Way 2
// Disadvantages and advantages are reversed from Way 1.
// Such as to add derived item, Add(std::unique_ptr<Item>(new DerivedItem));
// |
// easy to write DerivedItem here for an error
bool Add(std::unique_ptr<Item>& item);
// This is Way 3
// Similar to Way 2, but when failed to add, item still exist if it is a
// reference of outer unique_ptr<Item>
};
我个人选择的方式1.方式2和方式3的任何优势或方式1的缺点我应该选择2或3?
sftrabbit提供了很多好处。在以下常见情况中。如何使用方式2或3轻松完成?用户使用对话框生成新的派生项。它被放在std::unique_ptr<DerivedItem> item
上。单击“确定”按钮时,会将其添加到容器中。如果添加失败,请返回对话框进行编辑。
答案 0 :(得分:5)
我投票支持:
bool Add(std::unique_ptr<Item> item);
原因:
从函数签名中可以清楚地看出客户端需要将对象的所有权传递给MyContainer
。如果您选择选项1,则仍然不清楚客户端是否应该delete
对象本身,或者即使它们应该传递动态分配的对象。
如果客户已经拥有由命名std::move
管理的对象,则必须使用std::unique_ptr
明确转让所有权。他们不会意外失去所有权。选项3没有明确表示它将取得所有权。
当我们有std::make_unique
(N3588)时,添加元素的方法将是:
container.Add(std::make_unique<Item>());
这可以避免在某些情况下使用new
并提高异常安全性。
您为派生对象提供的问题并不是真正的问题。如果你做错了,你会得到一个编译时错误。
如果界面更改为使用其他类型的智能指针,则客户端将想要知道。他们不想继续传递认为他们通过所有权的对象,如果实际上他们正在共享它。他们特别想知道相反的情况是否相反。
答案 1 :(得分:2)
不幸的是,第一种方式严重危及类型安全 - 你已经指出我们自己处于劣势。我认为这些担忧压倒了这种方法可能带来的任何好处。
特别是,使用派生对象时第二种方法的潜在错误是在编译时捕获的,所以它很烦人,但安全!
我同意你的评估,这种用法泄漏了实施细节,但根据我的经验,这种泄漏是不可避免的 - 我同意sfrabbit这实际上是这个类的用户需要了解的细节。
答案 2 :(得分:1)
将此视为工具箱中的另一个工具:
bool Add(std::unique_ptr<Item>&& item);
这结合了方式2和方式3的优点。它只接受rvalue unique_ptr
s(如2),但是如果将它添加到容器中有一些失败,它可以保留所有权,如3.可以使用类似的东西:
void
foo(MyContainer& c)
{
std::unique_ptr<Item> p = get_Item();
try
{
c.Add(std::move(p));
}
catch (...)
{
log_error_wtih(*p);
}
}