C++ 智能指针列表-管理对象生存期和指针有效性
我有一个智能指针列表,其中每个指针指向一个单独的实体类C++ 智能指针列表-管理对象生存期和指针有效性,c++,list,constructor,c++11,smart-pointers,C++,List,Constructor,C++11,Smart Pointers,我有一个智能指针列表,其中每个指针指向一个单独的实体类 std::列出m_实体 我希望构造函数能够处理将每个指针分配给std::list类,因为它是由类实例化时的代码“自动”处理的。然而,如果这个设计不好,那么我会欢迎一个更好的选择,因为它只对我来自C#背景的人有意义 Entity::Entity(Game &game) : m_game(game), m_id(m_game.g_idGenerator->generateNewID())
std::列出m_实体代码>
我希望构造函数能够处理将每个指针分配给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));
}
Entity::Entity(游戏和游戏)
:m_游戏(游戏),
m_id(m_game.g_id生成器->generateNewID())
{
m_游戏。m_实体。推回(std::unique_ptr(this));
}
我在使用此方法时遇到的主要问题是,实体类的生存期不受实体类的管理
例如,如果我在堆栈上分配一个实体类,它将在离开分配它的方法后调用实体析构函数,指针将不再有效
因此,我考虑了创建智能指针的替代方案,将实体类分配到堆中,然后将指针显式添加到列表中
std::unique_ptr<Entity> b(new Entity(*this));
m_entities.push_back(b); // ERROR
std::unique_ptr b(新实体(*this));
m_实体。推回(b);//错误
这会产生以下错误
error C2664: 'void std::list<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'std::unique_ptr<_Ty>' to 'std::unique_ptr<_Ty> &&'
错误C2664:'void std::list::push_back('u Ty&&'):无法将参数1从'std::unique_ptr'转换为'std::unique_ptr&'
将每个指针分配到列表的最佳方法是什么?是否可以使用基于构造函数的版本
我目前认为应该处理每个实体类的生存期的智能指针列表,在构造函数中分配指针不是一个好的设计选择。在这种情况下,我可能应该创建一个CreateEntity方法,将指针添加到列表中,而不是让构造函数来处理它。这样更好吗
在通读了所发现的问题后,我考虑了什么类型的智能指针适用于此操作,以及(场外)。根据我目前所读的内容,很难得到准确的答案,因为它们都提供了一些相互矛盾的建议。我不会对您的设计问题发表评论,但要纠正错误,请将代码更改为:
m_entities.push_back(std::unique_ptr<Boundary>(new Boundary(*this, body)));
m_实体。推回(std::unique_ptr(新边界(*此,主体));
或:
std::unique_ptr b(新边界(*此主体));
m_实体。推回(std::move(b));
原因是代码中的b
是一个左值,但std::unique_ptr
是一个仅移动的类型(即没有复制构造函数)。要解决堆栈创建实例的问题,只需向构造函数添加一个参数,告诉它不要将新实例添加到列表中,例如:
Entity::Entity(Game &game, bool AddToList = true)
: m_game(game),
m_id(m_game.g_idGenerator->generateNewID())
{
if (AddToList) m_game.m_entities.push_back(this);
}
另一个选项可能是向实体添加析构函数,如果该析构函数仍然存在,则将其从列表中删除,但是,要避免直接实体
销毁和唯一
销毁之间的冲突,这可能会有点复杂。代码中的问题是,您试图将std::unique
从l值移动。std::unique_ptr
的实例化是不可复制的,只能移动。要从l值移动,需要显式执行以下操作:
this->m_entities.push_back(std::move(b));
调用std::move()
不会真正移动任何东西,但它会生成一种类型,向编译器指示对象可以移动。以这种方式使用构造函数肯定不是个好主意,因为构造函数没有关于如何创建和控制对象的信息-在堆栈上,静态地,通过智能指针动态地,通过哑指针动态地
要解决此问题,您可以使用静态工厂方法创建实体
实例:
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&);
};
类实体
{
公众:
//具有唯一所有权的变体
静态void CreateGameEntity(游戏和游戏)
{
std::unique_ptr p(新实体());
game.m_entities.push_back(std::move(p));
}
//或者(不能同时使用二者)
//共享所有权的变体
静态std::shared_ptr CreateGameEntity(游戏和游戏)
{
std::shared_ptr p(新实体());
游戏。m_实体。推回(p);
返回p;
}
私人:
//将CTOR声明为私有,以避免创建实体实例的可能性
//没有CreateGameEntity()方法,例如在堆栈上。
实体();
实体(const实体&);
};
使用哪种智能指针?这取决于你的设计。如果游戏
对象单独拥有实体
实例并完全管理它们的生命周期,则可以使用。如果您需要某种共享所有权(例如,您有几个游戏
对象可以共享相同的实体
对象),您应该使用
此外,如果是唯一所有权,您也可以使用。它包含专门的指针容器,如ptr\u vector
、ptr\u list
、ptr\u map
等。为什么您的代码使用std::unique\u ptr
但错误消息使用std::auto\u ptr
?这是您的真实代码吗std::unique_ptr
和std::auto_ptr
是不同的不相关类,您显示的代码使用的是std::unque_ptr
,但错误消息显示的是std::auto_ptr
。而Boundary
与Entity
有何关联?请看:错误的错误是在我更改指针类型以查看它们之间的差异时被错误复制的。道歉。它已被编辑以显示正确的错误。如果您需要某种共享所有权(例如,您有几个游戏对象可以共享相同的实体对象),则应使用std::shared\u ptr。其他类将通过拥有/保存所有指针的std:列表访问指针。这些其他类可以获取或设置公开的实体参数。他们是否需要拥有该对象才能执行此操作?@user1423893:“own”在本上下文中的意思是控制(或扩展)对象的
this->m_entities.push_back(std::move(b));
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&);
};