html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

RAII + С++ variadic templates = win tutorial

Недавно пристально посмотрел на С++ Variadic Templates и неожиданно для себя изобрел новый RAII Scoped Resource Manager.
Получилось кратко и эффектно.

Например, с C-style выделением памяти:
// Аллоцируем ресурс в блоке.
{
    ha::scoped_resource<void*, size_t> mem(::malloc, 1, ::free);

    ::memset(mem, 65, 1);
}


При выходе из блока ресурс будет освобожден автоматически.

Или еще вот так можно захватывать владение ресурсом «файловый дескриптор»:
// Захватываем ресурс в блоке.
{
    ha::scoped_resource<int> fd(
        [&filename]()
        {
            return ::open(filename.c_str(), O_RDONLY);
        },
        ::close);

    assert(fd != -1);

    std::vector<char> buff(1024);
    ssize_t rc = ::read(fd, &buff[0], 1024);
}


При выходе из блока ресурс будет освобожден автоматически даже после вызова, например, throw std::exception().

Или второй пример можно переписать даже понятней без применения лямбды:
{
    ha::scoped_resource<int, char*, int> fd(::open, filename.c_str(), O_RDONLY, ::close);

    if (fd == -1)
        throw std::runtime_error(std::string("open() failed: ") + ::strerror(errno));

    std::vector<char> buff(1024);
    ssize_t rc = ::read(fd, &buff[0], 1024);
}


То есть в общем случае имеем темплейтный класс, который инстанциируется типом ресурса, а его конструктор принимает две std::functions:initializer_t и finalizer_t.

Между инициализатором и финализатором следуют параметры для инициализатора, которые являются частью спецификаторов шаблона.

Деструктор просто вызывает финализатор для захваченного ресурса.

Для raw-доступа к ресурсу существует оператор типа ресурса.
{
    ha::scoped_resource
        <resource_t, param1_t, ...>
            resource
                (ititializer, param1, ..., finalizer);

    resource_t
        plain_resource =
            resource.operator resource_t();
}


В чем преимущество перед другими RAII реализациями враперов ресурсов?

  1. Инициализатор не вызывается во время редукции параметров конструктора, а в самом конструкторе. Это, например, позволяет реализовать «нормальную» передачу инициализатора, что дает возможность захвата ресурса в lazy-стиле, до первого вызова operator resource_t(). Еще это позволяет создавать именованные инициализаторы, тем самым переиспользуя их.
  2. Можно явно передавать какое-либо количество параметров для инициализатора. Тут, возможно, есть еще второй полезный механизм — std::initializer_list.
  3. Если пункт 2. по каким-то причинам не применим, можно в качестве инициализатора передавать лямбду, которая замкнет все параметры инициализатора на себя.
  4. Деинициализатор имеет единственный параметр — тип ресурса, но в случае необходимости также может быть лямбдой, замыкая на себя дополнительные параметры деинициализации.
  5. Это намного проще в реализации чем std::shared_ptr(T* ptr, deleter d).


Недостатки?
Иногда все же эффективней написать полноценный врапер ресурса.

Нужно больше примеров? Их есть у меня:

Создание AVFormatContext контекста:
ha::scoped_resource<ffmpeg::AVFormatContext*> formatctx
    (ffmpeg::avformat_alloc_context, ffmpeg::avformat_free_context);


Это есть аналог следующего:
std::shared_ptr<ffmpeg::AVFormatContext> formatctx =
    std::shared_ptr<ffmpeg::AVFormatContext>
        (ffmpeg::avformat_alloc_context(), ffmpeg::avformat_free_context);


Или вот еще, тут применяется составной деинициализатор:
ha::scoped_resource<ffmpeg::AVCodecContext*> codecctx(
        ffmpeg::avcodec_alloc_context,
        [](ffmpeg::AVCodecContext* c)
        {
            ffmpeg::avcodec_close(c),
                ffmpeg::av_free(c);
        });


А этот пример интересен тем, что происходит захват ресурса, который не нужно освобождать:
ha::scoped_resource<ffmpeg::AVCodec*, ffmpeg::AVCodecID> codec(
        ffmpeg::avcodec_find_decoder,
        codecctx->codec_id,
        [](__attribute__((unused)) ffmpeg::AVCodec* c)
        {
        });


И наконец самый простой oneliner:
ha::scoped_resource<ffmpeg::AVFrame*> frame(ffmpeg::avcodec_alloc_frame, ffmpeg::av_free);


Который аналог следующего:
std::shared_ptr<ffmpeg::AVFrame> frame =
    std::shared_ptr<ffmpeg::AVFrame>(ffmpeg::avcodec_alloc_frame(), ffmpeg::av_free);

Но неужели это все про naked plain-C ресурсы? А где же примеры с годным С++?
А вот:
ha::mutex mutex;

ha::scoped_resource<ha::mutex*, ha::mutex*> scoped_lock(
    [](ha::mutex* m) -> ha::mutex*
    {
        return m->lock(), m;
    },
    &mutex,
    [](ha::mutex* m) -> void
    {
        m->unlock();
    }
);

Хорошо, но где же реализация?
Реализация класса scoped_resource настолько проста и элегантна, что даже чем-то напомнила мне идею Y-combinator'a.
То есть возможно с легкостью реализовать что-то подобное, просто начав с декларации конструктора scoped_resource::scoped_resource(initializer_t, finalizer_t); и затем наращивать variadic-часть для параметров.

Хорошо, но где же все-таки реализация, а?
template <typename T, typename... A>
class scoped_resource
{
    public:
        typedef std::function<T (A...)> initializer_t;
        typedef std::function<void(T)> finalizer_t;
        typedef T resource_t;
        scoped_resource(initializer_t finit, A... args, finalizer_t final)
            : finit_(finit), final_(final), resource_(finit_(args...)) { };
        ~scoped_resource() { final_(resource_); }

        template <typename Y>
        Y get() const { return static_cast<Y>(resource_); }
        T get() const { return resource_; }
        operator T() const { return get(); }

        // No copy, no move
        scoped_resource(const scoped_resource&) = delete;
        scoped_resource(scoped_resource&&) = delete;
        scoped_resource& operator=(const scoped_resource&) = delete;
        scoped_resource& operator=(scoped_resource&&) = delete;

    private:
        const initializer_t finit_;
        const finalizer_t final_;
        T resource_;
};


Вот как-то так. image

Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

0

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции