return — есть ли стандартный класс C ++ для установки значения переменной при выходе из области

В рамках функции-члена я хочу временно установить переменную-член в определенное значение.

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

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

void MyClass::MyMemberFunction() {
struct SetBackToFalse {
SetBackToFalse(bool* p): m_p(p) {}
~SetBackToFalse() {*m_p=false;}
private:
bool* m_p;
};

m_theVariableToChange = true;
SetBackToFalse resetFalse( &m_theVariableToChange ); // Will reset the variable to false.

// Function body that may throw.
}

Это кажется настолько очевидным явлением, что мне было интересно, существует ли такой класс шаблонов, делающий это в стандартной библиотеке C ++?

12

Решение

Пока нет (были предложения для этого). Но реализовать универсальный достаточно просто;

struct scope_exit {
std::function<void()> f_;
explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {}
~scope_exit() { if (f_) f_(); }
};
// ...
m_theVariableToChange = true;
scope_exit resetFalse([&m_theVariableToChange]() { m_theVariableToChange = false; });

Для простоты выше я отредактировал конструкторы копирования и перемещения и т.д …

Отмечать их как = delete сделаем вышеуказанное минимальным решением. В дальнейшем; Перемещение может быть разрешено при желании, но копирование должно быть запрещено.


Более полный scope_exit будет выглядеть (онлайн демо здесь);

template <typename F>
struct scope_exit {
F f_;
bool run_;
explicit scope_exit(F f) noexcept : f_(std::move(f)), run_(true) {}
scope_exit(scope_exit&& rhs) noexcept : f_((rhs.run_ = false, std::move(rhs.f_))), run_(true) {}
~scope_exit()
{
if (run_)
f_(); // RAII semantics apply, expected not to throw
}

// "in place" construction expected, no default ctor provided either
// also unclear what should be done with the old functor, should it
// be called since it is no longer needed, or not since *this is not
// going out of scope just yet...
scope_exit& operator=(scope_exit&& rhs) = delete;
// to be explicit...
scope_exit(scope_exit const&) = delete;
scope_exit& operator=(scope_exit const&) = delete;
};

template <typename F>
scope_exit<F> make_scope_exit(F&& f) noexcept
{
return scope_exit<F>{ std::forward<F>(f) };
}

Примечания по реализации;

  • std::function<void()> может быть использован для стирания типа функтора. std::function<void()> предлагает исключительные гарантии для конструкторов перемещения, основанные на исключении, специфичном для удерживаемой функции. Образец этой реализации найден Вот
  • Эти спецификации исключений соответствуют предложениям C ++ и реализациям GSL
  • Я отредактировал большую часть мотивации для noexceptболее существенная деталь найдена в Предложение C ++
  • «Обычная» семантика RAII деструктора, следовательно, применима функция «выхода из области видимости»; Я не буду throwэто также согласуется со спецификацией C ++ 11 в спецификации исключений по умолчанию для деструктора. Увидеть cppreference, SO Q&, GotW # 47 а также HIC ++

Другие реализации могут быть найдены;

9

Другие решения

Вы могли бы «злоупотреблять» shared_ptr за это:

m_theVariableToChange = true;
std::shared_ptr<void> resetFalse(nullptr, [&](void*){ m_theVariableToChange = false; });

Если есть опасения по поводу использования void как параметр шаблона TЯ нашел следующее в стандарте C ++:

20.8.2.2§2:

… Параметр шаблона T для shared_ptr может быть неполного типа.

Это указывает на то, что T используется только как указатель, поэтому с помощью void все должно быть в порядке.

4

Там нет стандартной версии этого.

CppGoreGuidelines Библиотека поддержки (GSL) имеет обобщенную версию этого называется в конце концов но эта библиотека еще не является качественной продукцией. Это определенно рекомендуемая практика.

Е.19: Использовать final_action объект для экспресс очистки, если нет подходящего дескриптора ресурса

причина

finally менее многословен и труднее ошибиться, чем try/catch,

пример

void f(int n)
{
void* p = malloc(1, n);
auto _ = finally([p] { free(p); });
// ...
}

Заметка

finally не так грязно, как try/catch, но это все еще ad-hoc.
Предпочитаю правильные объекты управления ресурсами.

1

Подобный вопрос: Самый простой и удобный C ++ 11 ScopeGuard

В этом потоке описана похожая защита для вызова произвольной функции. Чтобы решить вашу проблему, вызовите лямбду, которая сбрасывает вашу переменную.

Например, решение от этот ответ для вашего кода будет:

scope_guard guard1 = [&]{ m_theVariableToChange = false; };

Другой ответ на этот поток отмечает, что аналогичная концепция была предложена для стандартизации C ++ 17; и также представлено решение C ++ 03.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector