В Loki можно найти полезную вещь - scope guard. Поясню зачем она нужна. Все знакомы с RAII и с тем, что очень удобно делать работу по управлению ресурсами в деструкторе - это безопасно с точки зрения исключений, так как при откате стека по исключению вызываются деструкторы всех уничтожаемых объектов. Например:
class FileФайл закроется даже в случае если Foo бросит исключение.
{
public:
File(const char* FileName) { OpenFile(FileName); }
~File() { CloseFile(); }
};
{
File f("test.txt");
Foo();
}
Однако создавать такие RAII-классы для каждого случая - довольно муторная работа. Представьте:
{Гораздо проще было бы жить, если бы можно было записать все это намного короче:
class Guard
{
public:
Guard(Module& M, Window& W) : m(M), w(W) {}
~Guard() { w.Close(); m.Terminate(); }
private:
Window& w;
Module& m;
}
Guard g(module, window);
Foo();
}
{Так вот предложенная Александреску конструкция такое счастье и привносит в нашу жизнь, выглядит это так:
AutoGuard(window.Close());
AutoGuard(module.Terminate());
Foo();
}
{Все бы замечательно, но это не компилируется без
LOKI_ON_BLOCK_EXIT_OBJ(window, Windows::Close);
LOKI_ON_BLOCK_EXIT_OBJ(module, Module::Terminate);
Foo();
using namespace Loki
, так как макрос LOKI_ON_BLOCK_EXIT_OBJ выглядит так:#define LOKI_ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard
А ведь дядька Александреску мог бы и пожалеть людей и написать так:
#define LOKI_ON_BLOCK_EXIT_OBJ ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeObjGuard
А ведь не написал. Видимо не использовал это в реальных проектах. Или у него там сплошные
using namespace xxx
стоят?PS. Оказывается уже исправили.
2 комментария:
имхо не очень удобно это все как раз, например если надо уметь сделать release().
или записать какую-то простейшую логику в dtor.
если уж надо сделать что-то вроде scope guard, то я обычно пишу прям в теле функции:
struct guard {
pointer_type ptr;
~guard() { if (ptr) { destroy_ptr(ptr); } }
} g_ = { some_ptr } ;
плюс именно в том, что можно писать все что угодно в этом деструкторе, а не только вызовы функций и если надо сделать release() - просто пишем g_.ptr = 0; и всех дел.
Да, release() иногда полезен. А scope guard из loki - он не на все случаи жизни, а для определенных ситуаций - и с ними он справляется одной строкой, в этом и прелесть.
Отправить комментарий