Какой самый короткий путь в C ++ 11 (или новее) для создания оболочки RAII без необходимости писать новый класс? - PullRequest
0 голосов
/ 12 декабря 2018

Часто я нахожусь в ситуации, когда мне нужна простая оболочка RAII, но я не хотел бы создавать целый новый класс для этого по многим причинам, включая ограничения по времени и организационные проблемы.Мое быстрое решение - следующее:

Скажем, я хочу убедиться, что к концу области я хочу, чтобы логическое значение вернулось в исходное состояние:

bool prevState = currState;
currState      = newState;
std::unique_ptr<int, std::function<void(int*)>> txEnder(new int(0), [&prevState](int* p) {
    currState = prevState;
    delete p;
});

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

Есть ли более чистый способ сделать это безнеобходимость написать целый класс и избавиться от new для манекена int?

Ответы [ 4 ]

0 голосов
/ 15 декабря 2018

Как насчет gsl::finally?Библиотека не такая тяжелая, как boost, и finally не использует std::function, поэтому может быть легко встроена.Также нет динамического выделения std::unique_ptr

using namespace std;

void foo(bool & currState, bool newState)
{
    auto revertState = gsl::finally([prevState = currState, &currState]{
        currState = prevState;
    });
    currState = newState;       
    cout << "currState: " << currState << endl;
}


int main() {
    bool state = false;
    foo(state, true);
    cout << "state: " << state << endl;
    return 0;
}

Онлайн-пример: https://ideone.com/Xi1izz (с копией gsl::finally, поскольку #include <gsl/gsl> здесь недоступно)

0 голосов
/ 12 декабря 2018

Чуть лучше, чем у вас: вы можете использовать &prevState в пользовательском деструкторе, не удаляя его, поэтому вам не нужно new и delete что-то:

void foo(bool & currState, bool newState)
{
    bool prevState = currState;
    currState      = newState;
    std::unique_ptr<bool, std::function<void(bool*)>> txEnder(&prevState, [&prevState, &currState](bool* p) {
        currState = prevState;
    });
    cout << "currState: " << currState << endl;
}

Вы такжезабыл захватить currState в лямбду.

Вот пример: https://ideone.com/DH7vZu

0 голосов
/ 12 декабря 2018

Не используйте std::function.Он создает много кода, включая vtables.https://gcc.godbolt.org/z/XgDoHz
Если вы абсолютно не хотите использовать какой-либо внешний класс или функцию, сделайте следующее:

bool foo_2() {
    bool f = false;
    auto eos = [&](void*){
        f = true;
    };
    std::unique_ptr<void, decltype(eos)> h{&eos,std::move(eos)};
    return f;
}

Если вы в порядке с небольшой функцией многократного использования, ниже работает.Это абстрагирует неиспользованный void*.

C ++ 14 или более поздняя версия

template<class F>
auto call_at_end_of_scope(F&& f){
    auto eos = [f{std::forward<F>(f)}](void*){f();};
    return std::unique_ptr<void, decltype(eos)>{&eos,std::move(eos)};
}

bool foo_3() {
    bool f = false;
    auto handle = call_at_end_of_scope([&](){
        f = true;
    });
    return f;
}
0 голосов
/ 12 декабря 2018

Вы можете использовать BOOST_SCOPE_EXIT

auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
     currState = prevState;
} BOOST_SCOPE_EXIT_END
...