odysset
@odysset
Программист, немного музыкант и bmx'ер

Как изменить значение у всех владельцев shared_ptr?

Пишу рендер, есть класс, который должен хранить шейдеры, что то вроде менеджера шейдеров. Эти шейдеры хранятся как
std::map<std::string, std::shared_ptr<BaseShader>> cache;

BaseShader - это абстрактный класс(имеются виртуальные методы).

Другие классы, хотят владеть шейдерами, и запрашивают их соответственно по имени. То есть у них у каждого хранится копия умного указателя. После изменения нужно шейдеры перезагрузить с диска. Соответственно, делается new и по имени записывается в cache, проблема в том, что клиенты не видят этого изменения. Как сделать так, чтобы не делался reset для умного указателя, а по тому же самому адресу, что он хранит, скопировался обновленный объект?
  • Вопрос задан
  • 322 просмотра
Пригласить эксперта
Ответы на вопрос 1
@menkar3
В принципе, для случая "shared_ptr, который может стать невалидным" и существует std::weak_ptr
Примитивное решение заключается в том, чтобы хранить std::shared_ptr только в кеше (который отвечает за владение объектом), а клиентам выдавать std::weak_ptr на него.
class Base
{
public:
    virtual ~Base() = default;
};

class Derived : public Base {};

int main()
{
    std::map<std::string, std::shared_ptr<Base>> cache;
    cache.insert(std::make_pair<std::string, std::shared_ptr<Base>>
        ("key", std::make_shared<Derived>()));
    std::weak_ptr<Base> ptr(cache["key"]);
    assert(cache["key"].get() == ptr.lock().get());
    // invalidation
    cache["key"].reset(new Derived);
    assert(ptr.expired());
    // check on every access
    if (ptr.expired())
        ptr = cache["key"];
    assert(cache["key"].get() == ptr.lock().get());
    return 0;
}

Проблемы:
  1. Маленькая проблема - перед каждым обращением к объекту нужно проверять expired() (ну, или проверять полученный после lock() shared_ptr на предмет пустоты)
  2. Большая проблема - многопоточность. Как между вызовами expired() и lock() так и при работе с shared_ptr, возвращенным lock() в любой момент может произойти инвалидация кеша. Простого решения сходу не вижу, выбор способа синхронизации остается за вами
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы