Использовать shared_ptr в макете Game Engine? - PullRequest
0 голосов
/ 14 февраля 2019

Я написал небольшой игровой движок на с ++, и он работает нормально, но это не самая лучшая производительность.Я также многому научился и хочу переделать это сейчас.Но в прошлый раз я интенсивно использовал shared_ptr для таких классов, как текстуры графического интерфейса и обертки моделей (которые содержат, например, 3d-позицию и opengl vao).Я слышал, что shared_ptr на самом деле не должен использоваться, но я действительно не знаю, как сделать это любым другим способом.Вот макет, подобный псевдокоду:

Этот код не завершен или не работает, но я хочу поделиться идеей моего макета

// d3 stands for 3d
class D3Model {
    VAO vao;
    bool useBloom;
    unsigned int texture;
    // ... and so on

    static std::vector<std::shared_ptr<D3Model>> models; // current idea, approach 1
    static std::vector<D3Model> models1; // different approach (2)

    D3Model() {
        models.push_back(shared_from_this()); // app.1
        models1.push_back(*this);
    }
}


// main file
int main() {
    std::shared_ptr<D3Model> model = std::make_shared<D3Model>();
    model->setTexture(0); // ignore the non sense content

    D3Model model1;
    model1.setTexture(0); // would not get updated in the vector

    while(true) {
        model->increaseRotation(1);
        model1.increaseRotation(1);
        Renderer::render();
    }
}

// different file
class Renderer {
    static void render() {
        for(const auto& all : D3Model::models) {
            // render model
        }

        for(const auto& all : D3Model::models1) {
            // render model1, would not have increased rotation
        }
    }
}

Для более ясного представления представьте следующее использованиеДвижок: после нажатия кнопки воспроизведения на стартовом экране движок загружает из файлов несколько 3d-моделей и сохраняет их.Один из них вращается каждый кадр, и каждый из них отображается.Может быть, некоторые другие модели должны быть загружены после из-за изменения в игровом процессе (игрок присоединился ...).Затем все они удаляются, когда пользователь возвращается в главное меню.Моя проблема с подходом 2 состоит в том, что мне придется обновлять вектор каждый раз, когда вращение модели увеличивается, тогда как это будет автоматически обрабатываться при подходе 1. Однако я слышал, что shared_ptr плохо влияет на производительность.

Является ли shared_ptr для этого случая лучшим решением или я должен просто использовать обычные объекты?Но моя проблема в том, как бы я применил изменения к объекту (например, setTexture) без необходимости обновления векторного содержимого.И сырые указатели тоже не очень хороши.Как это сделать?Спасибо, нереально

1 Ответ

0 голосов
/ 14 февраля 2019

Хорошо, вы можете создать свой собственный класс RefCouner, такой как я:

/// RefCounter.hpp
#pragma once
class RefCounter {
public:

    RefCounter();

    RefCounter(const RefCounter&);

    RefCounter& operator=(const RefCounter&);

    void grab();

    usize reference() const;

    bool release();

protected:

    virtual void finalize();

    virtual ~RefCounter();

private:

    usize _reference;

};


template<typename T>
struct ref {

    inline ref() : class_ptr (nullptr) {}

    inline ref(T* obj) : class_ptr (obj) { if(class_ptr) class_ptr->grab(); }

    inline ref(const ref& other) : class_ptr (other.class_ptr) { if(class_ptr) class_ptr->grab(); }

    inline ref& operator=(T* obj) {
        if(obj)
            obj->grab();
        if(class_ptr)
            class_ptr->release();
        class_ptr = obj;
        return *this;
    }

    inline ref& operator=(const ref& other){
        T* obj = other.class_ptr;
        if(obj)
            obj->grab();
        if(class_ptr)
            class_ptr->release();
        class_ptr = obj;
        return *this;
    }

    T* get() const {
        return class_ptr;
    }

    operator T*() const {
        return class_ptr;
    }

    T* operator->() const {
        return class_ptr;
    }

    inline ~ref() {
        if(class_ptr)
            class_ptr->release();
    }

private:
    T* class_ptr;
};

/// RefCounter.cpp


RefCounter::RefCounter() : _reference(0){

}

RefCounter::RefCounter(const RefCounter&) : _reference(0) {

}

RefCounter& RefCounter::operator=(const RefCounter&) {
    return *this;
}

void RefCounter::grab() {
    _reference++;
}

usize RefCounter::reference() const {
    return _reference;
}

bool RefCounter::release() {
    if(_reference > 1) {
        _reference--;
        return false;
    } else {
        _reference = 0;
        finalize();
        return true;
    }
}

void RefCounter::finalize() {
    delete this;
}

RefCounter::~RefCounter() {
}
...