我在DLL中有一个类看起来像这样的类:
#ifdef LIB_EXPORT
#define LIB_API __declspec(dllexport)
#else
#define LIB_API __declspec(dllimport)
#endif
...
class LIB_API MyClass {
public:
// ...public interface...
private:
// ...some private fields...
std::unique_ptr<OtherClass> otherPtr_;
};
现在,我认为这可能是一个问题:如果客户端代码使用稍微不同的unique_ptr版本,则MyClass对象的内存布局实际上会与DLL中的代码所期望的不同。
我真的不想诉诸Pimpl成语来隐藏公共标题中的unique_ptr
。我可能会推出自己的unique_ptr
简化版本(我只需要其功能的一部分,例如我不需要自定义删除工具)。但是,在我尝试之前,还有其他方法可以解决这个问题吗?
答案 0 :(得分:4)
您推测的问题非常真实,它不仅适用于标准库类的布局,还适用于您自己的类。除非您的类符合标准布局规则,否则不同的编译器不会使用相同的内存布局,即使给出完全相同的源代码也是如此。答案是不应该导出C ++类。
案例#1:如果您希望unique_ptr
管理DLL的公共对象的生命周期:
从DLL导出工厂函数和删除函数,并在公共头文件中放置一个包装器类。包装器完全存在于客户端内,因此仅使用客户端版本的unique_ptr
。
__declspec(dllexport)
未在包装类上使用。
案例#2:如果DLL在内部使用unique_ptr
:
您应该使用继承,而不是pimpl。公共头文件包含一个带有受保护构造函数的基类,纯虚拟成员函数,根本没有数据成员。同样,__declspec(dllexport)
未使用。 dllexport
工厂函数用于创建新实例。在DLL内部,您从此接口类型继承,派生类添加所有数据成员和函数体。客户端没有看到任何数据成员,因此您可以自由使用C ++对象,并且使用的布局是DLL的本地布局。
这两者的副作用是不会内联普通成员函数,这可能会对性能产生负面影响。但是为每个成员访问调用DLL是实现解耦的唯一方法。