以支持继承的方式将自身shared_ptr添加到对象构造函数中的向量中

Adding shared_ptr to self to vector in constructor of object in a way that supports inheritance

本文关键字:添加 ptr 构造函数 向量 对象 shared 继承 支持 方式      更新时间:2023-10-16

我希望在创建对象时自动将对已创建对象的引用添加到向量(通常是多个向量(中。为了提供一些上下文,此代码将在游戏中用于游戏对象集(可绘制、可碰撞、敌人等(,因此需要多个向量。

这里显示了我试图实现的目标的示例:

#include <iostream>
#include <memory>
#include <vector>
class BaseClass :public std::enable_shared_from_this<BaseClass>
{ //for example "drawable"
public:
BaseClass()
{
std::cout << "Base Created"<<std::endl;
BaseList.push_back(shared_from_this());//I want to put a reference to this object in a vector
}
~BaseClass()
{
std::cout << "Base Deleted"<<std::endl;
}
static std::vector<std::shared_ptr<BaseClass>> BaseList;
};
class DerivedClass :public BaseClass
{//for example "enemy"
public:
static std::vector<std::shared_ptr<BaseClass>> DerivedList; //shared_ptr of baseclass can point to derivedclass
DerivedClass()
{
std::cout << "Derived Created" << std::endl;
DerivedList.push_back(shared_from_this());//reference to this object in a vector in addition to the other vector
}
~DerivedClass()
{
std::cout << "Derived Deleted" << std::endl;
}
};
std::vector<std::shared_ptr<BaseClass>> BaseClass::BaseList;
std::vector<std::shared_ptr<BaseClass>> DerivedClass::DerivedList;
int main()
{
std::shared_ptr<BaseClass> C = std::make_shared<BaseClass>();
std::shared_ptr<BaseClass> D = std::make_shared<DerivedClass>();
BaseClass::BaseList.clear(); //C should be deleted, D should not since it is still in DerivedList
DerivedClass::DerivedList.clear(); //now D should be deleted
return 0;
}

在此代码中,shared_from_this()的使用无法正常工作,因为它位于构造函数中(如此处所示(。以前我已经使用单独的静态函数克服了这个问题,例如:

void BaseClass::makeOne()
{
std::shared_ptr<BaseClass> P(new BaseClass());
BaseClass::BaseList.push_back(P);
}
void DerivedClass::makeOne()
{
std::shared_ptr<BaseClass> P(new DerivedClass());
BaseList.push_back(P);
DerivedList.push_back(P);
}

然而,在从单个基类派生多个类的上下文中,并且每个派生类也可以添加到其他向量中,代码重复成为一个问题(BaseList.push_back(P)应该为每个继承BaseClass的对象调用,因此必须在X继承的每个X::MakeOne()中编写BaseClass(。

我也通过简单地使用原始指针(std::vector<BaseClass*>(来克服这个问题,但是当对象在多个地方被引用时,这失去了简单内存管理和引用计数的好处。在这种情况下,是否有更好的内存管理选择?

我认为这可以通过使用工厂/提供者来解决。

class SomeBaseClass // Could also be an interface or similar
{
};
// Instead of having SomeBaseClassFactory instance, all the methods could also be static
class SomeBaseClassFactory
{
public:
std::vector<std::shared_ptr<SomeBaseClass>> someBaseClassList;
std::shared_ptr<SomeBaseClass> GenerateObject(/* Parameters */)
{
std::shared_ptr<SomeBaseClass> someBaseClass = std::make_shared<SomeBaseClass>(/* Parameters */);
RegisterObject(someBaseClass);
return someBaseClass;
}
protected:
void RegisterObject(std::shared_ptr<SomeBaseClass> objectToRegister)
{
someBaseClassList.push_back(objectToRegister);
}
};
class SomeDerivedClass : public SomeBaseClass
{
};
class SomeDerivedClassFactory : public SomeBaseClassFactory
{
public:
std::shared_ptr<SomeDerivedClass> GenerateObject(/* Parameters */)
{
std::shared_ptr<SomeDerivedClass> someDerivedClass = std::make_shared<SomeDerivedClass>(/* Parameters */);
RegisterObject(someDerivedClass);
return someDerivedClass;
}
};

您可以像这样为对象定义工厂:

#include <iostream>
#include <memory>
#include <vector>
class Factory
{
public:
template<class T, class ... Args>
static std::shared_ptr<T> Make(Args... args)
{
auto instance = std::shared_ptr<T>(new T(args...));
T::List.push_back(instance);
return instance;
}
};
class BaseClass
{ 
friend class Factory;  
protected:    
BaseClass()
{
std::cout << "Base Created"<<std::endl;
}
public:
virtual ~BaseClass()
{
std::cout << "Base Deleted"<<std::endl;
}
static std::vector<std::shared_ptr<BaseClass>> List;
};
class DerivedClass : public BaseClass
{//for example "enemy"
friend class Factory;  
DerivedClass()
{
std::cout << "Derived Created" << std::endl;
}
public:
~DerivedClass()
{
std::cout << "Derived Deleted" << std::endl;
}
static std::vector<std::shared_ptr<BaseClass>> List; //shared_ptr of baseclass can point to derivedclass
};
std::vector<std::shared_ptr<BaseClass>> BaseClass::List;
std::vector<std::shared_ptr<BaseClass>> DerivedClass::List;
int main()
{
auto base = Factory::Make<BaseClass>();
auto derived = Factory::Make<DerivedClass>();
}