Прочитал, недавно, на хабре, статью про scope(exit) в языке D и проникся красотой идеи.
Ведь так часто бывает, что нужно выполнить какой-либо код по выходу из функции, а создавать каждый раз страж — утомительно, да и не всегда возможно.
Но, использую новый стандарт, в С++ можно сделать не хуже, кому интересно — прошу под кат.
Сама идея — очень простая, нужно создать класс, принимающий функтор в конструкторе, и выполняющий его в деструкторе.
Теперь можно написать что-то вроде:
Пока не очень удобно.
Раз уж на хабре неделя макросов, попробуем упростить использование с помощью них:
Теперь в коде можно написать так:
По-моему — намного лучше.
Вот только сам класс выглядит не очень, попробуем его причесать, используя std::function.
Раз уж зашла речь о boost( вернее о том, что с него пришло в стандарт ), нельзя не упомянуть, что в нём есть похожий механизм. Но он не использует преимущества нового стандарта, и использовать его, на мой вкус, не совсем удобно.
Используя boost/scope_exit.hpp можно было-бы написать такой код:
Из недостаков моей реализации можно назвать некоторый оферхэд на выполнение и проблема с эксепшенами в вызываемом коде.
Ведь так часто бывает, что нужно выполнить какой-либо код по выходу из функции, а создавать каждый раз страж — утомительно, да и не всегда возможно.
Но, использую новый стандарт, в С++ можно сделать не хуже, кому интересно — прошу под кат.
Сама идея — очень простая, нужно создать класс, принимающий функтор в конструкторе, и выполняющий его в деструкторе.
class exit_scope { public: template< typename Callback > exit_scope( const Callback& callback ):caller_( new caller<Callback>(callback) ){} ~exit_scope(){ caller_->call(); delete caller_; } private: exit_scope(); exit_scope(const exit_scope&); exit_scope& operator =(const exit_scope&); struct caller_interface { virtual ~caller_interface(){} virtual void call()=0; }; template< typename Callback > struct caller: caller_interface { caller( const Callback& callback ): callback_(callback){} virtual void call(){ callback_(); } Callback callback_; }; caller_interface* caller_; };
Теперь можно написать что-то вроде:
int test() { std::string omega; std::cin >> omega; exit_scope guard1 = [&](){ std::cout<< "First exit scope "<<omega<<std::endl; }; return 0; }
Пока не очень удобно.
Раз уж на хабре неделя макросов, попробуем упростить использование с помощью них:
#define EXIT_SCOPE_CREATE_UNIQ_NAME2(line) exit_scope_guard_##line #define EXIT_SCOPE_CREATE_UNIQ_NAME(line) EXIT_SCOPE_CREATE_UNIQ_NAME2(line) #define EXIT_SCOPE exit_scope EXIT_SCOPE_CREATE_UNIQ_NAME(__LINE__) = [&]()
Теперь в коде можно написать так:
int test1() { std::string omega; std::cin >> omega; EXIT_SCOPE{ std::cout << "Second exit scope" << omega<< std::endl; }; EXIT_SCOPE{ std::cout << "Third exit scope" << omega<<std::endl; }; return 0; }
По-моему — намного лучше.
Вот только сам класс выглядит не очень, попробуем его причесать, используя std::function.
class exit_scope { public: template< typename Callback > exit_scope( const Callback& callback ):callback_(callback){} ~exit_scope(){ callback_(); } private: exit_scope(); exit_scope(const exit_scope&); exit_scope& operator =(const exit_scope&); std::function<void(void)> callback_; };
Раз уж зашла речь о boost( вернее о том, что с него пришло в стандарт ), нельзя не упомянуть, что в нём есть похожий механизм. Но он не использует преимущества нового стандарта, и использовать его, на мой вкус, не совсем удобно.
Используя boost/scope_exit.hpp можно было-бы написать такой код:
int test1() { std::string omega; std::cin >> omega; BOOST_SCOPE_EXIT( (&omega) ) { std::cout << "Fourth exit scope" <<omega<< std::endl; } BOOST_SCOPE_EXIT_END return 0; }
Из недостаков моей реализации можно назвать некоторый оферхэд на выполнение и проблема с эксепшенами в вызываемом коде.
