智能指针列表 - 管理对象生命周期和指针有效性

use*_*893 2 c++ constructor list smart-pointers c++11

我有一个智能指针列表,其中每个指针都指向一个单独的实体类。

std::list<std::unique_ptr<Entity>> m_entities;

我希望构造函数能够处理每个指针对 std::list 类的分配,因为它是由类实例化的代码“自动”处理的。然而,如果这个设计很糟糕,那么我会欢迎更好的选择,因为它只对来自 C# 背景的我有意义。

Entity::Entity(Game &game) 
    : m_game(game),             
    m_id(m_game.g_idGenerator->generateNewID())             
{
    m_game.m_entities.push_back(std::unique_ptr<Entity>(this));
}
Run Code Online (Sandbox Code Playgroud)

我使用此方法遇到的主要问题是实体类的生命周期不受实体类管理。

例如,如果我在堆栈上分配一个实体类,它将在离开分配它的方法后调用实体析构函数,并且指针将不再有效。

因此,我考虑了另一种选择:创建智能指针,将实体类分配到堆,然后将指针显式添加到列表中。

std::unique_ptr<Entity> b(new Entity(*this));
m_entities.push_back(b);   // ERROR
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误

error C2664: 'void std::list<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'std::unique_ptr<_Ty>' to 'std::unique_ptr<_Ty> &&'
Run Code Online (Sandbox Code Playgroud)

将每个指针分配到列表的最佳方法是什么?基于构造函数的版本是否可能?

我目前认为智能指针列表应该处理每个实体类的生命周期,并且在构造函数中分配指针不是一个好的设计选择。在这种情况下,我可能应该创建一个 CreateEntity 方法,将指针添加到列表中,而不是让构造函数处理它。这是否更好?

在阅读了此处此处此处(场外)发现的问题后,我考虑了哪种类型的智能指针适合此操作。根据我到目前为止所读到的内容,很难得到准确的答案,因为它们都提供了一些相互矛盾的建议。

Ros*_*ost 5

以这种方式使用构造函数绝对不是一个好主意,因为构造函数没有关于如何创建和控制对象的信息 - 在堆栈上,静态地,通过某个智能指针动态地,通过哑指针动态地?

为了解决这个问题,你可以使用静态工厂方法来创建Entity实例:

class Entity
{
public:

   // Variant with unique ownership
   static void CreateGameEntity(Game& game)
   {
     std::unique_ptr<Entity> p(new Entity());
     game.m_entities.push_back(std::move(p));
   }

   // OR (you cannot use both)

   // Variant with shared ownership
   static std::shared_ptr<Entity> CreateGameEntity(Game& game)
   {
     std::shared_ptr<Entity> p(new Entity());
     game.m_entities.push_back(p);
     return p;
   }

private:

   // Declare ctors private to avoid possibility to create Entity instances
   // without CreateGameEntity() method, e.g. on stack.
   Entity();
   Entity(const Entity&);
};    
Run Code Online (Sandbox Code Playgroud)

使用哪种智能指针?嗯,这取决于你的设计。如果Game对象单独拥有Entity实例并完全管理它们的生命周期,则使用std::unique_ptr是可以的。如果您需要某种共享所有权(例如,您有多个Game可以共享相同对象的对象Entity),您应该使用std::shared_ptr.

另外,如果拥有独特的所有权,您可以使用Boost Pointer Container 库。它包含专门的拥有指针容器,如、ptr_vector等。ptr_listptr_map