使用智能指针包装C创建和销毁函数

时间:2017-08-26 07:51:23

标签: c++ c pointers smart-pointers cross-language

我有一些处理对象创建和销毁的C API,它提供:createObject(...)destroy(...)。我想将它包装成一些更现代的构造/破坏机制,并将它们与智能指针一起使用。我担心在某些时候我会忘记销毁这个物体,否则会发生一些例外。

我知道shared_ptr的自定义删除功能,但我无法显式调用new,因为createOjbect函数处理初始化。

在这种情况下我可以使用STL智能指针吗?从头开始,我是否必须在构造函数中实现初始化类,在析构函数中进行销毁以及在这种情况下引用计数?

3 个答案:

答案 0 :(得分:7)

std::shared_ptr完全能够创建和删除带有cutstom创建者和删除者的对象,但是你必须使用创建者函数而不是new

让我们考虑一下,我们有以下创作者和删除者:

typedef struct {
    int m_int;
    double m_double;
} Foo;

Foo* createObject(int i_val, double d_val) {
    Foo* output = (Foo*)malloc(sizeof(Foo));

    output->m_int = i_val;
    output->m_double = d_val;

    puts("Foo created.");
    return output;
}

void destroy(Foo* obj) {
    free(obj);
    puts("Foo destroyed.");        
}

要管理由上述函数创建的Foo实例,只需执行以下操作:

std::shared_ptr<Foo> foo(createObject(32, 3.14), destroy);

如果您不希望共享对象的所有权,则使用std::shared_ptr是一种开销。在这种情况下,std::unique_ptr要好得多,但对于此类型,您必须定义一个自定义删除工具,可以删除托管的Foo实例:

struct FooDeleter {
    void operator()(Foo* p) const {
        destroy(p);
    }
};
using FooWrapper = std::unique_ptr<Foo, FooDeleter>;

/* ... */

FooWrapper foo(createObject(32, 3.14));

答案 1 :(得分:3)

C ++ 17

template<auto X> using constant_t=std::integral_constant<std::decay_t<decltype(X)>, X>
template<auto X> constexpr constant_t<X> constant{};
template<class T, auto dtor> using smart_unique_ptr=std::unique_ptr< T, constant_t<dtor> >;

现在假设你有一个C Bob包裹Bob* createBob(some_args...)destroyBob(Bob*)

using unique_bob=smart_unique_ptr< Bob, destroyBob >;
unique_bob make_unique_bob(some_args args){
  return unique_bob( createBob(args) );
}

unique_bob可以隐式移入shared_ptr<Bob>

一些额外的假设可以使这在C ++ 14中起作用:

template<class T, void(*dtor)(T*)> using smart_unique_ptr=std::unique_ptr< T, std::integral_constant<decltype(dtor),dtor> >;

假设dtor签名为void(T*)

在C ++ 11中,你必须编写一个新的无状态函数指针调度程序,用于零开销的unqiue ptrs。

答案 2 :(得分:0)

为我的案例发布完整的解决方案:

根据@ Akira的建议,我使用共享指针包装它,因为我希望在许多宫殿中共享此对象,并且lambda:

// coming from some API:
struct SomeStruct;
bool initializedata(SomeStruct **data);
bool destorycdata(SomeStruct **data);

class SomeStructWrapper
{
public:
    SomeStructWrapper()
    {
        SomeStruct* data;
        if(initializedata(&data))
        {
            m_data = std::shared_ptr<SomeStruct>(data, [](SomeStruct* ptr){
                destorycdata(&ptr);
            });
        }
        else
        {
            throw std::runtime_error("Data was not initalized");
        }
    }

    const SomeStruct* operator->() const {return m_data.get();}
    SomeStruct* operator->() {return m_data.get();}

private:
    std::shared_ptr<SomeStruct> m_data;
};