Efficiently and elegantly emplaced unique_ptr returns

I found out ( https://stackoverflow.com/a/3/9129/ ) the security flaw in my code:

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

Basically, Itemraw allocation newmay leak memory if emplace_backthrown away.

The solution never uses raw new, but uses std::unique_ptron the right side of the method body.

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!
}

As you can see, the return is Itemnot valid, since I had to move Itemusing std::moveto put it in the container items.

I can not come up with a solution that requires storing the address Itemin an additional variable. The original (buggy) solution, however, is very concise and easy to read.

std::unique_ptr, ?

+4
3

:

template<class... TS>
Item& create(TS&&... mArgs)
{
    items.emplace_back(std::make_unique<Item>(std::forward<TS>(mArgs)...));
    return *items.back();
}
+8

, 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.
}
+2

++ 11, , make_unique, , ++ 14. , ++ 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() throw, Item unique_ptr.

+2

Source: https://habr.com/ru/post/1527961/


All Articles