Любой шаблон 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)
Ответ 6
Здесь еще один помощник C++ 11 RAII: https://github.com/ArtemGr/libglim/blob/master/raii.hpp
Он запускает функтор С++ при уничтожении:
auto unmap = raiiFun ([&]() {munmap (fd, size);});