[英]Efficiently and elegantly returning emplaced unique_ptr
我發現( 感謝StackOverflow注釋 )我的代碼中存在安全漏洞:
std::vector<std::unique_ptr<Item>> items;
template<class... TS> Item& create(TS&&... mArgs)
{
auto item(new Item(std::forward<TS>(mArgs)...);
items.emplace_back(item); // Possible exception and memory leak
return *item;
}
基本上,如果emplace_back
拋出,則使用raw new
分配Item
可能會泄漏內存。
解決方案永遠不會使用原始new
,而是在方法體中使用std::unique_ptr
。
std::vector<std::unique_ptr<Item>> items;
template<class... TS> Item& create(TS&&... mArgs)
{
auto item(std::make_unique<Item>(std::forward<TS>(mArgs)...);
items.emplace_back(std::move(item));
return *item; // `item` was moved, this is invalid!
}
如您所見,返回item
無效,因為我必須使用std::move
移動item
以將其放入items
容器中。
我想不出一個需要將item
地址存儲在附加變量中的解決方案。 然而,原始(錯誤)解決方案非常簡潔易讀。
是否有更優雅的方式返回一個std::unique_ptr
被移動以便放置在容器中?
你可以寫:
template<class... TS>
Item& create(TS&&... mArgs)
{
items.emplace_back(std::make_unique<Item>(std::forward<TS>(mArgs)...));
return *items.back();
}
在emplace之前緩存引用是更普遍適用的選項(例如,對於非向量容器):
template<class... TS> Item& create(TS&&... mArgs)
{
auto item = std::make_unique<Item>(std::forward<TS>(mArgs)...);
auto& foo = *item;
items.emplace_back(std::move(item));
return foo; // This *is* valid.
}
你的問題被標記為C ++ 11,其他答案表明make_unique
沒有提到它是C ++ 14的特性。 我相信這種C ++ 11方法也可以解決泄漏問題。
#include <vector>
#include <memory>
#include <utility>
#include <iostream>
struct Item
{
int a, b;
Item(int aa, int bb) : a{aa}, b{bb} { }
};
static std::vector<std::unique_ptr<Item>> items;
template <class... Ts> Item& create(Ts&&... args)
{
items.emplace_back(std::unique_ptr<Item>{new Item(std::forward<Ts>(args)...)});
return *items.back();
}
int main()
{
Item& x = create(1, 2);
std::cout << "( " << x.a << ", " << x.b << " )" << std::endl;
}
這應該是安全的,因為在構造unique_ptr<Item>
之前無法調用emplace_back()
,因此即使emplace_back()
拋出,您的Item
也已由unique_ptr
管理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.