Добавление shared_ptr к себе в вектор в конструкторе объекта способом, который поддерживает наследование - PullRequest
0 голосов
/ 27 июня 2018

Я хочу, чтобы ссылки на созданные объекты автоматически добавлялись в вектор (часто несколько векторов) при создании объектов. Чтобы придать некоторый контекст, этот код будет использоваться в игре для наборов игровых объектов (Drawable, Collidable, Enemies и т. Д.), Следовательно, потребуется несколько векторов.

Пример того, чего я пытаюсь достичь, показан здесь:

#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::MakeOne(), где X наследует BaseClass).

Я также преодолел эту проблему, просто используя необработанные указатели (std::vector<BaseClass*>), однако это теряет преимущество простого управления памятью и подсчета ссылок, когда на объекты ссылаются в нескольких местах. Есть ли лучший вариант для управления памятью в этой ситуации?

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Вы можете определить фабрику для своих объектов следующим образом:

#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>();
}
0 голосов
/ 27 июня 2018

Я думаю, что это можно решить с помощью Factory / Provider.

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;
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...