Аналог scope(exit) на С++

в 13:52, , рубрики: c++, макросы, С++, с++11, метки: , ,

Прочитал, недавно, на хабре, статью про 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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js