2015-07-29 5 views
6

У меня есть много LoadLibrary в моем проекте, и вам нужно позвонить FreeLibrary вручную для каждого LoadLibrary. Я хочу использовать std::unique_ptr с конкретным deleter, чтобы он автоматически освобождал мой ресурс dll.Можно ли использовать std :: unique_ptr для управления ресурсом DLL?

Это то, что я пытаюсь определить:

std::unique_ptr<HMODULE, BOOL(*)(HMODULE)> theDll(LoadLibrary("My.dll"), FreeLibrary); 

Но компилятор жалуется тип не соответствует. Я узнал, что он ожидает *HMODULE от LoadLibrary. То есть std::unique_ptr<A> будет ожидать A* в качестве своего типа указателя. По-видимому, мне еще нужно определить новый класс для управления ресурсом DLL (LoadLibrary в конструкторе и FreeLibrary в деструкторе).

Можно ли сделать std::unique_ptr<A>, чтобы просто ожидать, что его тип указателя A?

Обновлен,

Ниже плюсы и минусы для нового класса и с использованием зОго :: unique_ptr, обобщенных из ответов.

Создайте другой Dll класс управления,

плюсы:

  • Полностью управляемый, чтобы настроить для DLL семантического.
  • Изолируйте связанные с DLL части в класс с одной ответственностью.
  • Простота расширения, если требуется больше функциональности для DLL, например, для отображения символа.

минусы:

  • нужны перестраивать RAII часть, что Stadard авто указатель было сделано.
  • Имеет шанс совершить ошибку в RAII-части.
  • Need Объявить новый класс.

Использование std::unique_ptr с пользовательскими Deleter,

плюсы:

  • Нет необходимости объявить другой класс.
  • Повторно использовать часть RAII unique_ptr.
  • Возможно, move semantics предотвращает копирование экземпляра модуля DLL?

минусы:

  • Dll ресурс семантические может не соответствовать стандартному автоматическому указателю, и подвержены ошибкам?
  • Параметр шаблона в unique_ptr является сложным и трудно найти, где ошибка.
  • HMODULE is void*, тип типа типа, может быть проблемой для интеграции с unique_ptr?

Пожалуйста, исправьте меня в комментарии, если я ошибаюсь.

+2

, честно говоря, я считаю, что упаковка DLL в классе немного более безопасна из-за обработки ошибок, хотя она изначально выглядела элегантно, используя unique_ptr –

+0

@CyberSpock Полностью согласен. –

+0

До сих пор я обнаружил, что могу проверить, является ли 'theDll.get()' null или не знать, выполнено ли LoadLibrary? '. http://stackoverflow.com/a/11164463/2210478, , если 'theDll.get()' равно null, 'std :: unique_ptr' не будет вызывать deleter при указателе. Поэтому я не беспокоюсь, что передаю NULL в FreeLibrary. –

ответ

3

Вам необходимо предоставить соответствующий ::pointer типа для unique_ptr, если вы используете его, чтобы управлять ресурсом T, который не относится к T*. Здесь T является первым аргументом шаблона unique_ptr.

Если нет ::pointer тип не определен, используется T*. В вашем случае это HMODULE*, что неверно.

struct tLibraryDeleter 
{ 
    typedef HMODULE pointer; 
    void operator()(HMODULE h) { FreeLibrary(h); } 
}; 

std::unique_ptr<HMODULE, tLibraryDeleter>(::LoadLibraryA("My.dll")); 

Заканчивать here и here.

+0

Разделите разум, почему это нисходящее? –

+0

Да, это должно сработать. Но еще несколько строк кода, и у вас есть хороший, простой класс-оболочка вместо странных и подверженных ошибкам пользовательских удалений для 'DLL', что просто неправильно. –

+4

Я предлагаю вам переосмыслить то, что вы говорите. Я понятия не имею, почему и как вы считаете этот четко определенный пользовательский делетер «странным и подверженным ошибкам». Если вы действительно думаете об этом, по крайней мере покажите нам, как это может пойти не так. Если у вас есть какие-либо проблемы, посмотрите [здесь] (http://en.cppreference.com/w/cpp/memory/unique_ptr) и [здесь] (http://stackoverflow.com/questions/12184779/ используя-stdunique-PTR-для-окон-ручек). Дело в том, что вы изобретаете колеса, которые подвержены ошибкам. –

1

Похож мне еще нужно определить новый класс для управления библиотекой ресурсов

Почему вы думаете, что это плохая идея?

Почему бы не так?

class DynamicLibrary 
{ 
protected: 
    HANDLE  _handle; 
    string  _path; 

public: 
    DynamicLibrary(); 
    DynamicLibrary(const string& path, bool autoLoad = false); // if(autoLoad) this->Load() 

    ~DynamicLibrary(); // if(this->IsLoaded()) this->Unload() 

    Result Load(); // LoadLibrary() here 
    void Unload(); //FreeLibrary() here 

    bool IsLoaded() const; // return this->_handle != nullptr 
}; 

Затем, вы можете даже расширить этот класс, чтобы сделать символы извлечения уборщик:

class DynamicLibrary 
{ 
    //cut 

    void* RetrieveSymbol(const char* symName) const; 

    template <class Cast_type> 
    Cast_type RetrieveSymbolAs(const char* symName) const; 
}; 

Пример:

Явный тип предназначен для представления DLL экземпляра гораздо лучше, я думаю, , Затем вы можете сохранить массив таких объектов, и все будет автоматически. Чистый, простой, простой в использовании.

Хранение списка/массив std::unique_ptr<HANDLE, Some_custom_unloader> кажется мне плохим дизайном.

+1

В std :: unique_ptr реализовано удаление-на-destruct, поэтому я думаю, почему бы не просто повторно использовать его код и просто передать пользовательский Deleter. Чтобы определить typedef, чтобы скрыть свое сложное объявление, может быть меньше усилий для создания класса типа explict. –

+0

Вы избегаете ввода, но увеличиваете вероятность ошибок и уменьшаете ясность кода, скрывая очень важную и конкретную проблему в странных конструкциях вместо простого, простого в обслуживании, настраиваемого класса с единой ответственностью. Но это ваш код - ваш выбор. –

+1

хотя и не отвечает на его вопрос Я думаю, что это лучший способ +1 –

3

Согласно this page, HMODULE HINSTANCE, HINSTANCE - HANDLE, HANDLE PVOID, и PVOID недействителен *. Это означает, что HMODULE является типом указателя. Таким образом, следующее должно работать:

std::unique_ptr<std::remove_pointer_t<HMODULE>, BOOL(*)(HMODULE)> theDll(LoadLibrary("My.dll"), FreeLibrary);