如何使用RAII包装C分配返回错误代码

时间:2018-06-08 20:41:27

标签: c++ c raii

我意识到类似的问题已被问到elsewhere,但我找不到一个非常适合我的功能签名的答案。

考虑这对典型的C函数:

int initFoo(Options options, Foo* foo);
void freeFoo(Foo* foo);

initFoo需要一些选项和指向未初始化Foo结构的指针。它初始化此结构并返回一个结果代码,指示初始化是否成功。 freeFoo释放初始化的Foo结构。

现在假设我想在我的C ++代码中使用这些C函数。我想使用RAII,因此我需要构建一个unique_ptr<Foo>,它会在销毁时自动调用freeFoo。我能提出的最佳方法是:

template<typename T>
using lambda_unique_ptr = std::unique_ptr<T, std::function<void(T*)>>;

lambda_unique_ptr<Foo> createFoo(Options options) {
    Foo* foo = new Foo();
    const int resultCode = initFoo(options, foo);
    if (resultCode != 0) throw ...;

    return lambda_unique_ptr<Foo>(foo, [](Foo* foo) {
        freeFoo(foo);
        delete foo;
    });
}

我确信必须有更优雅的解决方案。理想情况下,更具功能性的东西不需要这么多单独的步骤。我发现特别难看的是必须在堆上显式分配Foo结构,然后显式释放并分两步删除它。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

你不能将Foo包裹在课程中吗?

struct FooWrap {
    Foo foo;

    explicit FooWrap(Options options) {
        if (initFoo(options, &this->foo))
            throw ...;
    }

    ~FooWrap() {
        freeFoo(&this->foo);
    }

    // XXX: either implement or disable assignment and copy construction
};

现在,您可以选择是将FooWrap x(42);定义为自动变量,还是选择是否使用new动态分配它。