我目前正在重新构建动态库项目,并从其标头中删除了大量STL和其他依赖项,导致不同工具链之间的实现冲突。
DLL接口现在只包含纯C类型和自定义类型,其实现仅依赖于DLL代码。但现在我仍然坚持剩下的两点。
#include <memory>
class Config;
typedef std::shared_ptr<Config> ConfigPtr;
class CONFIGAPI_DLL Config
{
public:
///...
ConfigPtr getNewNode( char const* query = "." )
{
// construct obj in dll, but construct shared_ptr in header
return ConfigPtr( _constructgetNewNode(query) );
}
ConfigPtr getNewNodeFromHeader( char const* query = "." )
{
// construct obj and shared_ptr in header
auto obj = new Config;
obj->_init(query);
return ConfigPtr( obj );
}
private:
Config* _constructNewNode( char const* query = "." );
void _init( char const* query = "." );
};
我在想通过在dll头文件中创建share_ptr( getNewNode )它会阻止std :: shared_ptr 的混合实现...但我不知道是否是个好主意?
但是我也在DLL中构造了新对象( _constructNewNode ),这意味着它也应该在那里被破坏?
我尝试在标题中构建它,因此在用户代码范围( getNewNodeFromHeader )中构建它...这不应该导致问题吗?
缺点是我仍然导出C ++ 11标头并排除所有旧编译器。是否可以将dll中的shared_ptr类型作为非冲突代码导出但仍与std :: shared_ptr兼容?
谢谢!
答案 0 :(得分:1)
我想你想要混合对象的创建和销毁(Config
和shared_ptr
)。如果DLL客户端没有使用相同的编译器版本和配置进行编译,则会遇到麻烦(例如,混合调试和发布模块)。我在这里看到的主要问题是:C ++没有任何类型的标准ABI。
我在想通过在dll头文件中创建share_ptr ( getNewNode )它会阻止std :: shared_ptr的混合实现 ...但我不知道这是不是一个好主意?
如果您定义头文件以创建shared_ptr,那么只有模块使用该头文件才可以。我的意思是,例如,如果不将shared_ptr用于DLL的内容。但是,如果其他客户端模块(二进制模块,如其他DLL)也使用该标头,则必须确保它们使用相同的编译器和编译配置进行编译。如果你没有这个保证,那就不是个好主意。
但是我也在DLL中构造了新对象(_constructNewNode) 这意味着它也应该在那里被破坏?
如果你在DLL中构造对象,你将更好地破坏DLL内部。怎么做?在shared_ptr
构造中指定删除器。像
struct ConfigDeleter {
void operator()(Config* c) {
c->destroy(); // or as you want to implement it.
};
typedef std::shared_ptr<Config, ConfigDeleter> ConfigPtr;
我尝试在标头中构建它,因此在用户代码范围内 (getNewNodeFromHeader)...这不应该导致问题吗?
和以前一样,这取决于您是否可以保证所有模块都是同类的(相同的编译器版本和配置,库等)。但是你想要实现它,做得好:
// construct obj and shared_ptr in header
auto obj_ = make_shared<Config>();
obj_->init(query);
它是异常安全且更高效的:只需一个分配来存储对象和引用,而不是样本中的两个分配。
如果您希望代码对于混合模块是安全的,请将所有分配(包括shared_ptr
)实现到DLL中(如果它们是共享的)。导出“C”接口,并创建头文件以将该接口包装在类中。类似的东西:
class WConfig {
public:
WConfig(): m(IDll->create()) {
}
// other member functions as interface stub
~WConfig() {
IDll->release(m);
}
private:
Config* m;
};
要共享此对象,您可以使用复制构造函数(例如,复制指针并调用IDll-&gt; reference(m))或任何其他方法。