Как стать автором
Обновить

Комментарии 27

Реализация класса scoped_resource настолько проста и элегантна, что даже чем-то напомнила мне идею Y-combinator'a.
Так где код-то?
Ожидал для себя увидеть не примеры использования, а основные идеи самой реализации да и просто сам код.
да вот же она, реализация! см. последний <code/code>.
все же хотелось не просто давать ответы, а и подтолкнуть к решению.
сам только решив эту задачу осознал насколько важно правильно поставить вопрос, который звучал так:
try
{
    int fd = ::open("file", ...);
    // i don't wrap it no more time
    throw exception();
}
catch(exception&)
{
  // oh no
}

А я вот не пишу на C и C++, и к сожалению даже с реализацией не уверен, что понял ваши манипуляции на 100% точно. А вы загадки загадывать.
да, это очень похоже, но работало с boost::lambda. теперь вижу там и std. спасибо.
А зачем вносить инициализацию в функтор — это лишнее усложнение.
Гораздо понятнее, когда есть только деструктор:

        FILE* f = fopen("file", "rb");
        if(!f) throw FileException();
        finally([&f] { fclose(f); });
        // reading file...


        BeginUpdate();
        finally([this] { EndUpdate(); });
        // updating...


намного легче понять и начать использовать.
Шаблон 'finally' правда хитрый, без препроцессора не обошлось (юзается __COUNTER__ и генерируется уникальное имя холдеру, чтобы не выдумывать самому, как это сделао в последней ссылке)
sqlite3* db;
sqlite3_open("some.db", &db);
scope(exit) sqlite3_close(db);


;)
Александреску жжот, конечно. Но это выглядит неконсистентным. Не?
Неконсистентным с чем?
само понятие блока скоупа конфликтует с языком где есть gc. в D ведь есть gc?
Понятие scope ортогонально наличию gc. В D есть gc. есть стек, есть malloc. А так же множество других ресурсов помимо памяти, которые нужно освобождать (файловые дескрипторы, сокеты и т.п.). Т.к. все классы — ссылочные типы, это даже не конфликтует с привычной по C++ семантикой, там ведь тоже указатели не освобождаются при выходе из scope и вроде никого это не беспокоит.
Ничего не конфликтует. Деструктор же не имеет отношения к памяти. Он просто выполняет некоторый код, когда обьект становится недоступен системе.
Или не выполняет. Поэтому в GC-языках не деструкторы, а финализеры и костыли типа try-finally / using. Я не про D
инициализатор вида std::function нужен по двум причинам:
1. lazy, если это нужно
2. нормальная редукция самого инициализатора, когда нужен код, который ближе к wrapped чем сам хак.
в моем примере это видно там, где mutex…

короче, это более предсказуемо в плане sequence point, но также позволяет использовать инплейсные лямбды, без их вызова, что усложняет чтение кода. все написанное и есть о том как избежать первым параметром T, а применить λx.T.
не минусуйте, пожалуйста, комментаторов.
этоа статья задумывалась как «пост добра», где каждый находит свой дзэн C++.
где однозначного вывода нету, будь вы коммитером boost.phoenix или первокурсником со struct something {};
Зачем там везде типы. Используйте auto.
это не тот случай. там везде типы на своих местах, нет?
инстанциация шаблона типом пока еще недоступна для вывода типов.
Ой, извините, действительно, перепутал.
Но если переписать через функцию, то можно обойтись и без явного указания типов. (Это я и имел ввиду)
scoped_resource(const scoped_resource&) = delete;

А что за "= delete"? это из последнего стандарта фича? извините, просто давно на С++ активно не писал.
Да, это одна из фич C++11 — позволяет запретить вызов функции, в данном случае запрещает конструктор копирования.
прикольно, но чем отличается от shared_ptr c deleter?

Или же это способ показать как можно сильно упростить задачу с С++ 0х11 без всяких bind? Это же прототип? Так как подсчета ссылок нету.
> прикольно, но чем отличается от shared_ptr c deleter?
тем, что shared_ptr всегда выделяет память в куче, плюс поддерживает счётчик ссылок. unique_ptr — тоже выделяет память под объект. scoped_ptr (boost?) с deleter'ом был бы аналогом, вот только есть разница между
ha::scoped_resource<int, char*, int> fd(::open, filename.c_str(), O_RDONLY, ::close);
и
scoped_ptr<int> fd(::open(filename.c_str(), O_RDONLY), [](int fd_) { ::close(fd_); });

Первое лаконичнее, хотя вариант с «func, arg1, arg2» может сбить с толку без привычного «func(arg1, arg2)».
Как-то очень уж вычурно.
Почему бы не засунуть освобождение ресурсов в лямбду или любую другую сущность с operator() без параметров? Или иначе статьи для хабра состряпать не получилась бы?

Вот вариант для Objective-C.
Header
Implementation

Где-то в закромах валялся такой же, но на шаблонах и для любого объекта-функции. Работал задолго до появления C++11. Если будет интерес — откопаю да выложу «на посмотреть».
конечно покажите. интересно
> finit_(finit), final_(final), resource_(finit_(args...))
как лаконично.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.