2014-09-29 129 views
3

我对unique_ptr的std :: list有个奇怪的问题。无法理解如何向std :: list添加新对象<std :: unique_ptr <classname>>

Class slFlyingMonster派生自类slMonster。

下面的代码工作:

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

但这代码:

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

抛出错误:

"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> &&'"

虽然我明白了,什么是错的,比如std ::名单.push_back()与=不一样,但我无法弄清楚如何正确地将新类作为unique_ptr添加到列表中。任何建议将非常受欢迎。

回答

4

使用push_back当你有一个列表包含的类型的对象,并且你想推送它的副本。通常情况下,如果你没有这样的对象,但(在你的情况,你没有),你最好使用emplace_back,而不是在列表中—直接初始化一个新的对象:

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

然而,正如@SebastianRedl在评论中正确指出的那样,上面有一个不是异常安全的问题。如果std::list内部新节点的内部分配抛出,则新的slFlyingMonster实例将被泄漏。 emplace_back当其中一个参数是不受保护的资源(例如拥有内存的原始指针)时不是正确的选择。

所以你实际上想要构造一个包装智能指针并将其推入列表中。在C++ 14,你可以用std::make_unique做到这一点:

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

用纯C++ 11,你可以实现自己的make_unique,或明确创建智能指针:

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

'mMonsters。push_back({new slFlyingMonster(md)});'不会编译。该构造函数是'explicit'。 – 2014-09-29 07:16:37

+0

@ T.C。非常感谢,修复。我在印象列表 - 初始化允许显式构造函数。我站在更正 – Angew 2014-09-29 07:46:08

+1

这不是异常安全的。 'list'在构造元素之前必须分配一个新节点,这可能会抛出新的对象被泄漏。 – 2014-09-29 12:29:16

4

您可以使用emplace_back

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

或一个的push_back std::make_unique

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

std::unique_ptr

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

构造std::unique_ptr<T>(T*)是明确的std::move,所以T*不能隐式构建std::unique_ptr

+0

它会如果你还解释了'emplace_back(T && ...)'和'push_back(T &&)'之间的区别是什么,那么更好。 – 2014-09-29 07:16:39

+0

'push_back(make_unique ...)'是最好的解决方案。第一个不是异常安全的。第三个过于冗长,除非你在创建对象和添加对象之间做更多的事情。 – 2014-09-29 12:26:53

相关问题