Как обернуть распределение C, возвращая код ошибки, используя RAII - PullRequest
0 голосов
/ 08 июня 2018

Я понимаю, что подобные вопросы задавались в другом месте , но я не смог найти ответ, который бы подходил для моих сигнатур функций.

Рассмотрим эту типичную пару функций 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 голосов
/ 08 июня 2018

Разве вы не можете просто обернуть 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.

...