Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot understand how to add new object to std::list<std::unique_ptr<classname>>

I have strange issue with std::list of unique_ptr's.

Class slFlyingMonster is derived from class slMonster.

Following code works:

std::unique_ptr<slMonster> ptr(new slFlyingMonster(md));

But this code:

std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(new slFlyingMonster(md));

throws error:

"Error 1 error C2664: 'void
std::list>,std::allocator>>>::push_back(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'slFlyingMonster *' to 'std::unique_ptr> &&'"

While I understand, that something is wrong, like std::list.push_back() is not the same as =, but I cannot figure out how to correctly add new class as unique_ptr to list. Any suggestions would be very welcome.

like image 601
Starl1ght Avatar asked Dec 26 '22 04:12

Starl1ght


1 Answers

Use push_back when you have an object of the type which your list contains, and you want to push its copy. Normally, if you don't have such an object yet (in your case, you don't), you're better off initialising a new object directly in the list — using emplace_back instead:

std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.emplace_back(new slFlyingMonster(md));

However, as @SebastianRedl correctly pointed out in the comments, the above has a problem of not being exception-safe. If the internal allocation of a new node inside std::list throws, the new slFlyingMonster instance would be leaked. emplace_back is not the correct choice when one of the arguments is an unprotected resource (such as a raw pointer owning memory).

So you actually want to construct a wrapper smart pointer and push it into the list. In C++14, you can do this with std::make_unique:

std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(std::make_unique<slFlyingMonster>(md));

With plain C++11, you can either implement your own make_unique, or explicitly create the smart pointer:

std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.emplace_back(std::unique_ptr<slMonster>(new slFlyingMonster(md)));
like image 81
Angew is no longer proud of SO Avatar answered Mar 12 '23 06:03

Angew is no longer proud of SO