如何使用智能指针跟踪 class 的对象?
How do I track objects of a class using smart pointers?
我正在尝试编写一个 class,其对象相互了解(即具有指向所有对象的指针)。我无法理解关于智能指针和静态成员的这个想法的某些方面。
class可以认为是一个游戏对象,需要能够访问其他游戏对象的成员函数和属性。
据我所知,实现所需设计的常用方法是静态向量,它包含指向其他对象的指针。如果通过原始指针操作,任务不是很复杂:
GameObject.h:
#pragma once
#include <vector>
class GameObject
{
private:
static std::vector< GameObject* > objects;
public:
GameObject()
{
objects.push_back(this);
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< GameObject* > GameObject::objects = {};
这实际上可以满足我的需要。但是如果我想使用智能指针,事情对我来说就没那么简单了。来自 this question and from the 'Effective Modern C++' book by Meyers I found out about std::enable_shared_from_this
and shared_from_this()
. But, additionally, the reference 明确指出 shared_from_this()
仅在对象已由 std::shared_ptr<>
.
拥有的情况下才允许使用
因此不可能以与之前相同的方式在构造函数中简单地推入静态向量 this
指针(或在其上构建的 std::shared_ptr
)。我发现允许设计的最小代码集如下:
GameObject.h:
#pragma once
#include <vector>
#include <memory>
class GameObject : public std::enable_shared_from_this<GameObject>
{
private:
static std::vector< std::shared_ptr<GameObject> > objects;
public:
GameObject() {}
void emplace_ptr()
{
objects.emplace_back(shared_from_this());
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< std::shared_ptr<GameObject> > GameObject::objects = {};
main.cpp:
#include "GameObject.h"
int main(int argc, char* argv[])
{
std::shared_ptr<GameObject> game_object{ new GameObject{} };
game_object->emplace_ptr();
return 0;
}
所以我显然不得不在外部某处创建一个指向对象的指针,然后显式调用一个方法将指针推送到静态向量(因为我不允许在构造函数中这样做)。
我觉得所需的代码变得不必要地复杂(与原始指针的情况相比)或者我在做一些荒谬的事情。
- 我努力让对象相互感知有意义吗
在所有?这是一个常见问题还是其他一些方法通常是
拍了?
- 静态向量是解决问题的可靠方法吗?
- 如何使用智能指针构造此类向量,但最好是,
无需外部干预,也无需创建
特殊功能
emplace_ptr()
的用途?
你不需要 enable_shared_from_this
,相反你可以有一个 static
工厂函数来创建(共享)实例,把它放在向量中,并且 returns 它.
类似
class GameObject
{
private:
static std::vector<std::shared_ptr<GameObject>> objects;
// Don't allow creation from outside
GameObject() {}
public:
static std::shared_ptr<GameObject> create()
{
objects.emplace_back(new GameObject);
return objects.back();
}
};
然后获取一个实例,例如
auto new_game_object = GameObject::create();
只有一个问题:共享指针指向的对象只要在向量中就永远不会超出范围,向量的生命周期就是程序的生命周期(因为它是 static
)。所以你必须考虑何时何地从向量中删除这些实例。
我会首先将静态向量移到游戏对象之外 class,并避免将管理游戏对象的代码放在游戏对象本身内部。另一个用户提出的静态 create() 方法会有所帮助,但我个人更喜欢自己调用 GameObject/Derived 游戏对象构造函数的能力,这样我就可以在构造过程中传递我需要的任何数据。
创建类似 GameObjectWorld class 的东西,您可以在游戏引擎执行期间向其中添加对象。无需直接从 GameObject 构造函数自动将它们添加到世界中。
你可以这样做:
auto gameObject = std::make_shared<GameObject>();
// implemented at a singleton for simplicity
GameObjectWorld::getInstance().add(gameObject);
过去,我采用了给定游戏 "Part" 或 "Scene" 维护其自己的游戏对象(实体)列表的方法,而这些游戏对象又维护自己的列表。这允许您通过递归执行操作,并具有对象层次结构的额外好处。
这是一个简单粗暴的例子:
class Part
{
std::vector<std::shared_ptr<GameObject> children;
public:
void addChild(std::shared_ptr<GameObject> object)
{
children.push_back(object);
}
// Part lifecycle
virtual void onCreate() = 0; // must be provided by your parts
};
class GamePart :: public Part
{
void onCreate() override; // called by your engine
};
void GamePart::onCreate()
{
addChild(std::make_shared<GameObject>());
}
这是开始管理游戏对象的一种非常简单的方法,我强烈建议您阅读 "Entity Component Systems" 并了解行业专家管理其游戏世界的一些方法。
我正在尝试编写一个 class,其对象相互了解(即具有指向所有对象的指针)。我无法理解关于智能指针和静态成员的这个想法的某些方面。
class可以认为是一个游戏对象,需要能够访问其他游戏对象的成员函数和属性。
据我所知,实现所需设计的常用方法是静态向量,它包含指向其他对象的指针。如果通过原始指针操作,任务不是很复杂:
GameObject.h:
#pragma once
#include <vector>
class GameObject
{
private:
static std::vector< GameObject* > objects;
public:
GameObject()
{
objects.push_back(this);
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< GameObject* > GameObject::objects = {};
这实际上可以满足我的需要。但是如果我想使用智能指针,事情对我来说就没那么简单了。来自 this question and from the 'Effective Modern C++' book by Meyers I found out about std::enable_shared_from_this
and shared_from_this()
. But, additionally, the reference 明确指出 shared_from_this()
仅在对象已由 std::shared_ptr<>
.
因此不可能以与之前相同的方式在构造函数中简单地推入静态向量 this
指针(或在其上构建的 std::shared_ptr
)。我发现允许设计的最小代码集如下:
GameObject.h:
#pragma once
#include <vector>
#include <memory>
class GameObject : public std::enable_shared_from_this<GameObject>
{
private:
static std::vector< std::shared_ptr<GameObject> > objects;
public:
GameObject() {}
void emplace_ptr()
{
objects.emplace_back(shared_from_this());
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< std::shared_ptr<GameObject> > GameObject::objects = {};
main.cpp:
#include "GameObject.h"
int main(int argc, char* argv[])
{
std::shared_ptr<GameObject> game_object{ new GameObject{} };
game_object->emplace_ptr();
return 0;
}
所以我显然不得不在外部某处创建一个指向对象的指针,然后显式调用一个方法将指针推送到静态向量(因为我不允许在构造函数中这样做)。
我觉得所需的代码变得不必要地复杂(与原始指针的情况相比)或者我在做一些荒谬的事情。
- 我努力让对象相互感知有意义吗 在所有?这是一个常见问题还是其他一些方法通常是 拍了?
- 静态向量是解决问题的可靠方法吗?
- 如何使用智能指针构造此类向量,但最好是,
无需外部干预,也无需创建
特殊功能
emplace_ptr()
的用途?
你不需要 enable_shared_from_this
,相反你可以有一个 static
工厂函数来创建(共享)实例,把它放在向量中,并且 returns 它.
类似
class GameObject
{
private:
static std::vector<std::shared_ptr<GameObject>> objects;
// Don't allow creation from outside
GameObject() {}
public:
static std::shared_ptr<GameObject> create()
{
objects.emplace_back(new GameObject);
return objects.back();
}
};
然后获取一个实例,例如
auto new_game_object = GameObject::create();
只有一个问题:共享指针指向的对象只要在向量中就永远不会超出范围,向量的生命周期就是程序的生命周期(因为它是 static
)。所以你必须考虑何时何地从向量中删除这些实例。
我会首先将静态向量移到游戏对象之外 class,并避免将管理游戏对象的代码放在游戏对象本身内部。另一个用户提出的静态 create() 方法会有所帮助,但我个人更喜欢自己调用 GameObject/Derived 游戏对象构造函数的能力,这样我就可以在构造过程中传递我需要的任何数据。
创建类似 GameObjectWorld class 的东西,您可以在游戏引擎执行期间向其中添加对象。无需直接从 GameObject 构造函数自动将它们添加到世界中。
你可以这样做:
auto gameObject = std::make_shared<GameObject>();
// implemented at a singleton for simplicity
GameObjectWorld::getInstance().add(gameObject);
过去,我采用了给定游戏 "Part" 或 "Scene" 维护其自己的游戏对象(实体)列表的方法,而这些游戏对象又维护自己的列表。这允许您通过递归执行操作,并具有对象层次结构的额外好处。
这是一个简单粗暴的例子:
class Part
{
std::vector<std::shared_ptr<GameObject> children;
public:
void addChild(std::shared_ptr<GameObject> object)
{
children.push_back(object);
}
// Part lifecycle
virtual void onCreate() = 0; // must be provided by your parts
};
class GamePart :: public Part
{
void onCreate() override; // called by your engine
};
void GamePart::onCreate()
{
addChild(std::make_shared<GameObject>());
}
这是开始管理游戏对象的一种非常简单的方法,我强烈建议您阅读 "Entity Component Systems" 并了解行业专家管理其游戏世界的一些方法。