我的情况如下:我有一个.dll文件和一个带有纯虚拟class MainWindow
声明的.h标头。头文件中有两个类型定义:
typedef MainWindow* (*CREATE_INTERFACE)();
typedef void (*DELETE_INTERFACE)(MainWindow* Window);
允许我创建和删除与虚拟类相同类型的对象。
我希望在我的课程中定义对此动态库的加载支持,我们称其为class Loader
。我希望我的一个类成员成为定义如下的智能指针:
std::unique_ptr <MainWindow,DELETE_INTERFACE> UI_Driver;
下面的简化代码(无错误处理):
class Loader
{
private:
HINSTANCE DllHandle;
CREATE_INTERFACE FactoryFunction;
DELETE_INTERFACE CustomDeleterFunction;
std::unique_ptr<MainWindow,DELETE_INTERFACE> UI_Driver;
std::unique_ptr<MainWindow,DELETE_INTERFACE> LoadExternalLibrary()
{
std::wstring WideFileName=L"MainWindow.dll";
std::string FileName(std::begin(WideFileName),std::end(WideFileName));
this->DllHandle=::LoadLibrary(WideFileName.c_str());
// Get the function from the DLL
FactoryFunction=reinterpret_cast<CREATE_INTERFACE>(::GetProcAddress(DllHandle,"Create"));
CustomDeleterFunction=(DELETE_INTERFACE)GetProcAddress(DllHandle,"Delete");
return std::unique_ptr<MainWindow,DELETE_INTERFACE>(FactoryFunction(),CustomDeleterFunction);
};
UI_Service() : UI_Driver(LoadExternalLibrary())
{
}
~UI_Service()
{
if(UI_Driver)
::FreeLibrary(this->DllHandle);
}
void ShowWindow()
{
UI_Driver->Show();
}
};
该代码正确编译,从.dll库加载函数也成功。标头中定义的MainWindow
具有绘制用户界面的Show()
方法。如果尝试使用ShowWindow()
中的class Loader
方法像上面一样调用它,则不会出现该窗口。
int main()
{
Loader MyLoader;
MyLoader.ShowWindow(); // <- window does not appear, program crashes
}
但是如果在LoadExternalLibrary()
方法中创建指针后立即调用此方法,则会显示如下:
所以改为:
return std::unique_ptr<Eol_MainWindow_Driver_Generic,DELETE_INTERFACE>(FactoryFunction(),CustomDeleterFunction);
我可以写:
std::unique_ptr<Eol_MainWindow_Driver_Generic,DELETE_INTERFACE> UI(FactoryFunction(),CustomDeleterFunction);
UI->Show(); // <- Window appears
return UI; // <- It will never happen because the Show() is blocking the thread
发生了什么事?为什么创建的带有自定义删除程序的unique_ptr在复制后会停止工作?
通过返回unique_ptr
,您可能会销毁它。
// funky indent to fit in SO width
return std::unique_ptr<
Eol_MainWindow_Driver_Generic,DELETE_INSTANCE
>(
FactoryFunction(),CustomDeleterFunction
);
除非您使用兼容C ++ 17的编译器进行编译,否则您无法保证1在调用者站点进行复制后创建的临时unique_ptr
不会被销毁。在这种情况下,您需要移动指针:
// funky indent to fit in SO width
return std::move(std::unique_ptr<
Eol_MainWindow_Driver_Generic,DELETE_INSTANCE
>(
FactoryFunction(),CustomDeleterFunction
));