来自DLL的智能指针:在哪里构建和;毁坏

时间:2014-03-28 08:45:37

标签: c++11 dll smart-pointers

我目前正在重新构建动态库项目,并从其标头中删除了大量STL和其他依赖项,导致不同工具链之间的实现冲突。

DLL接口现在只包含纯C类型和自定义类型,其实现仅依赖于DLL代码。但现在我仍然坚持剩下的两点。

  1. DLL应返回某种引用计数智能指针(带弱指针选项)
  2. 管理DLL边界之间的构造和破坏。这或多或少看起来像这样。
  3. #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兼容?

    谢谢!

1 个答案:

答案 0 :(得分:1)

我想你想要混合对象的创建和销毁(Configshared_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))或任何其他方法。