Любой шаблон RAII в boost или C ++ 0x - PullRequest
14 голосов
/ 23 января 2010

Есть ли какой-либо шаблон, доступный в boost для RAII. Есть классы типа scoped_ptr, shared_ptr, которые в основном работают с указателем. Могут ли эти классы использоваться для любых других ресурсов, кроме указателей. Есть ли какой-нибудь шаблон, который работает с общими ресурсами.

Возьмем, к примеру, некоторый ресурс, который получен в начале области и должен быть каким-то образом освобожден в конце области. Как приобрести, так и выпустить, предпринять некоторые шаги. Мы могли бы написать шаблон, который принимает два (или, возможно, один объект) функтора, которые выполняют эту задачу. Я не продумал, как это можно сделать, мне просто интересно, существуют ли какие-либо методы для этого

Edit: Как насчет одного в C ++ 0x с поддержкой лямбда-функций

Ответы [ 6 ]

12 голосов
/ 23 января 2010

shared_ptr предоставляет возможность указать пользовательское средство удаления . Когда указатель должен быть уничтожен, удалитель будет вызван и может выполнить любые необходимые действия по очистке. Таким образом, с помощью этого класса интеллектуальных указателей можно управлять более сложными ресурсами, чем простыми указателями.

8 голосов
/ 13 марта 2011

Более общая и более эффективная (без вызова через указатель на функцию) версия выглядит следующим образом:

#include <boost/type_traits.hpp>

template<typename FuncType, FuncType * Func>
class RAIIFunc
{
public:
   typedef typename boost::function_traits<FuncType>::arg1_type arg_type;
   RAIIFunc(arg_type p) : p_(p) {}
   ~RAIIFunc() { Func(p_); }
   arg_type & getValue() { return p_; }
   arg_type const & getValue() const { return p_; }
private:
   arg_type p_;
};

Пример использования:

RAIIFunc<int (int), ::close> f = ::open("...");
7 голосов
/ 23 января 2010

Наиболее общим подходом является ScopeGuard one (основная идея в этой статье djj , реализованная, например, с удобными макросами в Boost.ScopeExit ), и позволяет Вы выполняете функции или очищаете ресурсы при выходе из области действия.

Но, если честно, я не понимаю, почему ты этого хочешь. Хотя я понимаю, что каждый раз писать класс для одношагового и одноступенчатого паттерна немного раздражает, вы говорите о многошаговом опускании и -релизе.
Если он предпринял несколько шагов, он, по моему мнению, принадлежит к служебному классу с подходящим названием, так что детали скрыты, а код на месте (что снижает вероятность ошибки).
Если вы сравните это с прибылью, вам не о чем беспокоиться.

5 голосов
/ 23 января 2010

Я должен признать, что на самом деле не вижу смысла. Написание оболочки RAII с нуля уже смехотворно просто. Просто не нужно много работы с помощью какой-то предопределенной оболочки:

struct scoped_foo : private boost::noncopyable {
  scoped_foo() : f(...) {}
  ~scoped_foo() {...}

  foo& get_foo() { return f; }

private:
  foo f;
};

Теперь ... - это, по сути, биты, которые нужно было бы заполнить вручную, если бы вы использовали какой-то общий шаблон RAII: создание и уничтожение нашего ресурса foo. А без них действительно мало что осталось. Несколько строк стандартного кода, но он настолько мал, что просто не стоит его извлекать в повторно используемый шаблон, по крайней мере, на данный момент. С добавлением лямбда-выражений в C ++ 0x мы могли бы написать функторы для создания и уничтожения настолько кратко, что может стоить того, чтобы написать их и вставить их в повторно используемый шаблон. Но до тех пор кажется, что это будет больше проблем, чем стоит. Если бы вы определили два функтора для подключения к шаблону RAII, вы бы уже написали большую часть этого стандартного кода дважды .

4 голосов
/ 10 сентября 2010

Я думал о чем-то похожем:

template <typename T>
class RAII {
    private:
        T (*constructor)();
        void (*destructor)(T);
    public:
        T value;
        RAII(T (*constructor)(), void (*destructor)(T)) : 
                    constructor(constructor), 
                    destructor(destructor) {
            value = constructor();
        }
        ~RAII() {
            destructor(value);
        }
};

и использоваться следующим образом (на примере GLUquadric в OpenGL):

RAII<GLUquadric*> quad = RAII<GLUquadric*>(gluNewQuadric, gluDeleteQuadric);
gluSphere(quad.value, 3, 20, 20)
3 голосов
/ 29 июня 2013

Вот еще один помощник C ++ 11 RAII: https://github.com/ArtemGr/libglim/blob/master/raii.hpp

При разрушении запускается функтор C ++:

auto unmap = raiiFun ([&]() {munmap (fd, size);});
...