2015-09-07 2 views
1

Я пытаюсь экспортировать класс из DLL. Я читал эту статью на этом: http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLLКак обрабатывать деструкторы в экспортированных DLL-интерфейсах

«зрелый» подход предполагает, что используется абстрактный класс, так что у меня есть:

// Header 
class IFoo{ 
public: 
    virtual int getBar() = 0; 
} 

class Foo: public IFoo {...} 

DLLEXPORT IFoo* Create(); 
DLLEXPRT void Free(IFoo* inst); 

//DLL cpp 
IFoo* Create(){ return new Foo; } 
void Free(IFoo* inst){ delete inst; } 

озадачивает меня: Если я не виртуальные destructor, то delete inst не будет вызывать деструктор Foos и может протечь память. Как я должен справиться с этим? Статья не дает ответа на это.

Использование virtual ~IFoo(){} не представляется возможным, поскольку это добавляет реализация к IFoo, который вызывает проблемы (объяснение в ответ на вопрос, в статье для виртуальной функции инлайн) и virtual ~IFoo() = 0; завершается с ошибкой линкера на неопределенный символ ~IFoo

Что такое безопасный способ? Как должны быть реализованы функции Free/Release?

+1

Не делать вещи более сложными, чем они нуждаются быть. Просто предоставьте виртуальный деструктор в 'IFoo' и экспортируйте его определение. –

+0

Вместо этого вы можете добавить виртуальную функцию Free(). Кастинг * inst * to Foo * - это еще один способ, а не лучше. –

+0

@HansPassant: Почему бы не просто виртуальный деструктор? –

ответ

3

Прежде всего, отметим, что проблема связана с обработкой DLL Visual Studio. GCC и Clang имеют стабильную ABI (Itanium ABI), которая гарантирует совместимость библиотек, скомпилированных с различными версиями.

Теперь, как уже упоминалось, проблема, с которой вы сталкиваетесь, - это нестабильность ABI, однако части ABI стабильны (виртуальная таблица), иначе представленная стратегия просто не сработает.

Следовательно, просто необходимо, чтобы деструктор virtual работал. Из-за вызова через виртуальную таблицу не будет проблемы с изменением имени.

Кроме того, обратите внимание, что в современном C++ возвращает указатель сырец является нет-нет, но имя коверкание предотвращает использование смарт-указатель ...

// Foo.h 
class Foo { 
public: 
    virtual int get() = 0; 
    virtual ~Foo(); 

protected: 
    Foo() = default; 
    Foo(Foo&&) = default; 
    Foo(Foo const&) = default; 
    Foo& operator=(Foo) = default; 
}; 

// WARNING: immediately capture this Foo* in a smart pointer, 
//   or suffer from memory leak (and worse). 
Foo* createFoo(); // factory behind 

// Foo.cpp 
Foo::~Foo() {} // not inline 
+0

Итак, решение - это просто виртуальный деструктор, реализованный в DLL-библиотеках cpp? И я застрял с банком C++ 03, могу ли я достичь тех же защищенных конструкторов? Inline-реализация запрещена, я думаю ... – Flamefire

+0

@Flamefire: Я бы подумал, что должен работать не встроенный деструктор; проблема, которую я вижу с встроенным деструктором, заключается в том, что она будет генерировать многократный код для деструктора: один раз за DLL, и поскольку они используют несовместимые версии ... как и для C++ 03, просто не используйте 'Foo (Foo &&) 'constructor, и, конечно, полностью напишите тело (поскольку у вас не будет' = default'). –

Смежные вопросы