如何使用智能指针跟踪类的对象?

Posted

技术标签:

【中文标题】如何使用智能指针跟踪类的对象?【英文标题】:How do I track objects of a class using smart pointers? 【发布时间】:2016-07-06 17:53:34 【问题描述】:

我正在尝试编写一个其对象相互了解的类(即有一个指向所有对象的指针)。关于智能指针和静态成员,我无法理解实现这个想法的某些方面。

这个类可以被认为是一个游戏对象,它需要能够访问其他游戏对象的成员函数和属性。

据我所知,实现所需设计的常用方法是静态向量,其中包含指向其他对象的指针。如果通过原始指针操作,任务不是很复杂:

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 和 Meyers 的“Effective Modern C++”一书中,我发现了std::enable_shared_from_thisshared_from_this()。但是,另外,the reference 明确指出,shared_from_this() 仅允许在对象已由 std::shared_ptr&lt;&gt; 拥有的情况下使用。

因此不可能像以前一样在构造函数中简单地推入静态向量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 = ;

ma​​in.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()有什么用途?

【问题讨论】:

你可以通过构造构造函数private来摆脱enable_share_from_this,并提供静态构造函数来提供向量。 @Jarod42,我猜你的意思是静态命名构造函数(或创建函数),否则我同意 100%。 【参考方案1】:

您不需要enable_shared_from_this,而是可以使用static 工厂函数来创建(共享)实例,将其放入向量中,然后返回它。

类似

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();

这里只有一个问题:共享指针指向的对象只要在vector中就永远不会超出范围,而vector的生命周期就是程序的生命周期(因为它是@ 987654325@)。所以你必须考虑在何时何地从向量中删除这些实例。

【讨论】:

【参考方案2】:

我会首先将静态向量移到 GameObject 类之外,并避免将管理游戏对象的代码放入游戏对象本身。另一个用户提出的静态 create() 方法会有所帮助,但我个人更喜欢自己调用 GameObject/Derived 游戏对象构造函数的能力,这样我就可以在构造过程中传递我需要的任何数据。

创建类似 GameObjectWorld 类的东西,您可以在游戏引擎执行期间将对象添加到其中。无需直接从 GameObject 构造函数自动将它们添加到世界中。

你可以这样做:

auto gameObject = std::make_shared<GameObject>();
// implemented at a singleton for simplicity
GameObjectWorld::getInstance().add(gameObject);

过去,我采用的方法是给定游戏“部分”或“场景”维护它自己的游戏对象(实体)列表,而这些游戏对象(实体)又维护自己的列表。这允许您通过递归执行操作,并具有对象层次结构的额外好处。

这是一个粗略而简单的例子:

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>());

这是开始管理游戏对象的一种非常简单的方法,我强烈建议您阅读“实体组件系统”并了解行业专家管理游戏世界的一些方式。

【讨论】:

以上是关于如何使用智能指针跟踪类的对象?的主要内容,如果未能解决你的问题,请参考以下文章

C++单线程智能指针实现

C++ --- C++智能指针

018-智能指针

浅谈ObjectARX智能指针AcDbObjectPointer的用法

垃圾回收器设计

c++ 中啥样的指针是裸指针,参数可以是智能指针的引用吗,求高手举例指教