4

( 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;
}

基本的にItem、raw で を割り当てると、throwのnew場合にメモリ リークが発生する可能性がありますemplace_back

解決策は raw を使用することはありませんが、メソッド本体で権利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て移動する必要があったため、返すことは無効です。itemstd::moveitems

itemのアドレスを追加の変数に格納する必要がある解決策は考えられません。ただし、元の(バグのある)ソリューションは非常に簡潔で読みやすいです。

std::unique_ptrコンテナに定置するために移動されたを返すよりエレガントな方法はありますか?

4

3 に答える 3

8

あなたは書くことができます:

template<class... TS>
Item& create(TS&&... mArgs)
{
    items.emplace_back(std::make_unique<Item>(std::forward<TS>(mArgs)...));
    return *items.back();
}
于 2014-02-20T17:29:43.757 に答える
2

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.
}
于 2014-02-20T17:36:00.890 に答える
2

あなたの質問には 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;
}

これは、 が既に構築さemplace_back()れるまで呼び出すことができないため、安全である必要があります。unique_ptr<Item>emplace_back()Itemunique_ptr

于 2014-02-20T18:04:43.853 に答える