Любой шаблон RAII в boost или С++ 0x

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

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

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

Ответы

Ответ 1

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

Ответ 2

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

#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("...");

Ответ 3

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

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

Ответ 4

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

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

  foo& get_foo() { return f; }

private:
  foo f;
};

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

Ответ 5

Я думал о чем-то подобном:

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);
        }
};

и использовать его (используя OpenGL GLUquadric в качестве примера):

RAII<GLUquadric*> quad = RAII<GLUquadric*>(gluNewQuadric, gluDeleteQuadric);
gluSphere(quad.value, 3, 20, 20)