2015-01-29 3 views
1

Я реализовал простой ResourceManager - все было в порядке, пока я не попытался реализовать его деструктор для (экстренной) очистки (например, в случае фатального исключения). Я не смог найти ни одного способа сделать это:
Как освободить ресурсы от shared_ptr ResourceManager

template<typename T> 
class ResourceManager 
{  
public: 
    std::unordered_map<std::string, std::weak_ptr<T> > resource_map; 
    std::shared_ptr<T> getResource(std::string name) 
    { 
     std::shared_ptr<T> res = resource_map[name].lock(); 
     if(!res) 
     { 
      res = std::shared_ptr<T>(new T(this, name)); 
      resource_map[name] = res; 
     } 
     return std::move(res); 
    } 

    void Release(std::string name) 
    { 
     resource_map.erase(name); 
    }; 
    ~ResourceManager(void) { /* ???? */} 
}; 

class Texture 
{ 
private: 
    ResourceManager<Texture> * manager_; 
    std::string name_; 

public: 
    Texture(ResourceManager<Texture> * manager, std::string& name) 
      : manager_(manager), name_(name) { } 
    ~Texture(void){ 
     manager_->Release(name_); 
    } 
}; 

Очевидно, я должен перебрать все активные ресурсы ... но как я могу освободить их, если ResourceManager не является технически (единоличный) владелец ресурсов? Это может быть недостатком дизайна, если это так, предложите альтернативу.

EDIT: в ответ на ответы, чтобы определить «диспетчер ресурсов». Я представляю себе авторитетный кеш-хранилище для ссылок на ресурсы, которые могут искать ресурсы (= нет дубликатов) и управляет их состоянием в памяти (in-memory, description -одно (= путь + тип) и освобождается), все вышеописанное максимально автоматизировано. (Там должны быть отдельные ResourceLoaders, но это не изменится на этот вопрос)

+0

Лично я не вижу в этом хорошего дизайна. В чем смысл совместного владения, если кто-то может уничтожить подстилающий объект произвольно? Я не думаю, что это хорошая идея перевернуть концепцию совместного владения как это. Подумайте о том, чтобы вместо этого вернуть только ссылку, weak_ptr или * resource handle *, и пусть менеджер ресурсов сохраняет право собственности. – glampert

+0

[Это] (http://scottbilas.com/publications/gem-resmgr/) также может быть вам полезен. – glampert

+0

@ glampert хорошо, это статья 2000 года - она ​​реализует собственные 'weak_ptr' с помощью дескрипторов, поскольку они не были частью std до C++ 11 (по крайней мере, для google sais). Это почти то же самое, что и раздавать 'weak_ptr' и' .lock() 'ing. Но это то, что я изначально пытался избежать - необходимость проверять ресурс перед каждым использованием. – wondra

ответ

2

Итак, ваш код не делает много, чтобы осветить ваш общий дизайн, здесь, но ...

Как реализовано, ваш менеджер ресурсов, по-видимому, имеет слабые указатели на ресурсы. Это указывает на то, что он не несет ответственности за время жизни самих реальных ресурсов и поэтому не должен очищать эти ресурсы в своем деструкторе.

Если вы хотите, менеджер ресурсов будет авторитетным владельцем данных ресурса, вы захотите изменить его дизайн/реализацию. Например, вы можете хранить его shared_ptr s самим ресурсам и только передавать weak_ptr s клиентам. Или просто сохраните unique_ptr s и передайте голые указатели на код клиента.

Но, как написано, вам не нужно (и действительно не может) ничего сделать, чтобы очистить ресурсы в ~ResourceManager().

+0

Ну, если я раздаю 'weak_ptr', я должен проверить, находится ли ресурс в памяти каждый раз, когда я решаю использовать его, не так ли? Может ли это быть автоматизировано/синхронизировано таким образом, чтобы я сохранял преимущества раздачи 'shared_ptr'? (= нет необходимости проверять каждое использование и иметь представление о том, сколько активных пользователей ресурса есть?) – wondra

+0

Да, клиентам необходимо заблокировать() слабый указатель. Невозможно избежать проверки, если вы хотите, чтобы клиент мог узнать, мертв ли ​​указатель * и * использовать модель централизованного владения вместо общей. –

2

Чтобы предложить альтернативы, нам нужно знать, какую цель должен иметь ваш менеджер ресурсов.

  1. Вы хотите, чтобы он функционировал как «коллекция ресурсов», т. Е. Сохраняя ресурсы до тех пор, пока они не будут явно выпущены?
  2. Или вы хотите, чтобы это был «кеш ресурсов», сохраняя ресурсы до тех пор, пока он не решит, что некоторые должны быть выпущены для освобождения памяти?
  3. Или вы действительно хотите, чтобы он не поддерживал какие-либо ресурсы, а просто сохранил список ресурсов, которые, возможно, были живы чем-то другим?

Помните, что shared_ptr s на C++ не работает, как работает GC. То есть если вы уничтожите/перезагрузите последний shared_ptr объекту, этот объект будет удален немедленно, даже если есть weak_ptr s ему.

Таким образом, подходы (1) и (2) могут иметь большой смысл. (3), однако, это то, что вы в настоящее время имеете, очень редко имеет смысл (если вообще).

+0

Первоначально у меня возникло искушение полностью автоматическим освобождением. Позже я понял, что это не чудесное решение. Будет ли собственный GC с 'weal_ptr' хорошей идеей? Я попробовал реализовать собственный стареющий gc, но ДОЛЖЕН быть ресеяном, почему все аналогичные менеджеры используют выше. – wondra