Прочитал, недавно, на хабре, статью про scope(exit) в языке D и проникся красотой идеи.
Ведь так часто бывает, что нужно выполнить какой-либо код по выходу из функции, а создавать каждый раз страж — утомительно, да и не всегда возможно.
Но, использую новый стандарт, в С++ можно сделать не хуже, кому интересно — прошу под кат.
Сама идея — очень простая, нужно создать класс, принимающий функтор в конструкторе, и выполняющий его в деструкторе.
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" << std::endl; };
EXIT_SCOPE{ std::cout << "Third exit scope" << std::endl; };
return 0;
}
По-моему — намного лучше.
Вот только сам класс выглядит не очень, попробуем его причесать, использую библиотеку boost.
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&);
boost::function0<void> callback_;
};
Раз уж зашла речь о boost, нельзя не упомянуть, что в нём есть похожий механизм. Но он не использует примущества нового стандарта, и использовать его, на мой вкус, не совсем удобно.
Используя boost/scope_exit.hpp можно было-бы написать такой код:
int test1()
{
std::string omega;
std::cin >> omega;
BOOST_SCOPE_EXIT( (&omega) )
{
std::cout << "Fourth exit scope" << std::endl;
} BOOST_SCOPE_EXIT_END
return 0;
}
Из недостаков моей реализации можно назвать некоторый оферхэд на выполнение и проблема с эксепшенами в вызываемом коде.
Автор: DarkRIP