在导出的类中使用std :: unique_ptr

时间:2015-03-21 19:13:11

标签: c++ dll

我在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简化版本(我只需要其功能的一部分,例如我不需要自定义删除工具)。但是,在我尝试之前,还有其他方法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:4)

您推测的问题非常真实,它不仅适用于标准库类的布局,还适用于您自己的类。除非您的类符合标准布局规则,否则不同的编译器不会使用相同的内存布局,即使给出完全相同的源代码也是如此。答案是不应该导出C ++类。


案例#1:如果您希望unique_ptr管理DLL的公共对象的生命周期:

从DLL导出工厂函数和删除函数,并在公共头文件中放置一个包装器类。包装器完全存在于客户端内,因此仅使用客户端版本的unique_ptr

__declspec(dllexport)未在包装类上使用。


案例#2:如果DLL在内部使用unique_ptr

您应该使用继承,而不是pimpl。公共头文件包含一个带有受保护构造函数的基类,纯虚拟成员函数,根本没有数据成员。同样,__declspec(dllexport)未使用。 dllexport工厂函数用于创建新实例。在DLL内部,您从此接口类型继承,派生类添加所有数据成员和函数体。客户端没有看到任何数据成员,因此您可以自由使用C ++对象,并且使用的布局是DLL的本地布局。


这两者的副作用是不会内联普通成员函数,这可能会对性能产生负面影响。但是为每个成员访问调用DLL是实现解耦的唯一方法。