1 апр. 2009 г.

Использование boost::utility

Все объявления в хидере <boost/utility.hpp> включены в пространство имен boost.

Содержание

Шаблоны функций checked_delete() и checked_array_delete()

Заголовный файл <boost/checked_delete.hpp> содержит определение двух шаблонов функций checked_delete и checked_array_delete, и два шаблона классов: checked_deleter и checked_array_deleter.

Стандарт C++ (в 5.3.5/5) разрешает освобождать указатели на неполные типы через delete. Когда класс имеет непустой деструктор или определенный для класса оператор delete, поведение такой операции становится неопределенным. Некоторые компиляторы печатают предупреждение, когда удаляется неполный тип, но, к несчастью, это делают не все компиляторы, а программисты иногда игнорируют или блокируют предупреждения.

В частности, проблемным случаем является использование деструктора в шаблоне умного указателя, такого как boost::scoped_ptr<T>::~scoped_ptr, для неполностью определенного типа. Это зачастую приводит к трудно обнаруживаемым сбоям в работе программ.

Предлагаемая функция и шаблон класса могут быть использованы для предотвращения этих проблем, потому что они требуют передачи им полностью определенного типа, и генерируют ошибку компиляции в противном случае.

Краткое описание

namespace boost
{
 template<class T> void checked_delete(T * p);
 template<class T> void checked_array_delete(T * p);
 template<class T> struct checked_deleter;

 template<class T> struct checked_array_deleter;
}

checked_delete

template<class T> void checked_delete(T *p);

Требует: T должен быть полным типом (complete type). Выражение delete p должно быть синтаксически верным.

Эффекты: delete p;

checked_array_delete

template<class T> void checked_array_delete(T * p);

Требует: T должен быть полным типом. Выражение delete [] p должно быть синтаксически верным.

Эффекты: delete [] p;

checked_deleter

template<class T> struct checked_deleter
{
    typedef void result_type;
    typedef T * argument_type;
    void operator()(T * p) const;
};

void checked_deleter<T>::operator()(T * p) const;

Требует: T должен быть полным типом (complete type). Выражение delete p должно быть синтаксически верным.

Эффекты: delete p;

checked_array_deleter

template<class T> struct checked_array_deleter
{
    typedef void result_type;
    typedef T * argument_type;
    void operator()(T * p) const;
};

void checked_array_deleter<T>::operator()(T * p) const;

Требует: T должен быть полным типом. Выражение delete [] p должно быть синтаксически верным.

Эффекты: delete [] p;

Благодарности

Шаблоны функций checked_delete и checked_array_delete изначально были частью boost/utility.hpp, и документация была разработана с участием Beman Dawes, Dave Abrahams, Vladimir Prus, Rainer Deyke, John Maddock, и др.

Шаблоны функций next() и prior()

Определенные типы данных, такие как итераторы категорий forward и bidirectional стандартной библиотеки C++,  не поддерживают операции сложения и вычитания через  operator+() или operator-().  Это означает, что не-модифицирующие вычисления последующего и предыдущего значения требуют создания временного объекта, даже если operator++() или operator--() допустимы. Это также означает, что написание кода типа itr+1 внутри шаблона ограничивает категорию итератора в рамках random access.

Функции next() и prior() предоставляют простой способ избежать этих проблем:

template <class T>
T next(T x) { return ++x; }

template <class T, class Distance>

T next(T x, Distance n)
{
    std::advance(x, n);
    return x;
}

template <class T>
T prior(T x) { return --x; }

template <class T, class Distance>
T prior(T x, Distance n)
{
    std::advance(x, -n);
    return x;
}

Использование предельно просто:

const std::list<T>::iterator p = get_some_iterator();
const std::list<T>::iterator prev = boost::prior(p);
const std::list<T>::iterator next = boost::next(prev, 2);

Расстояние от заданного итератора должно быть задано абсолютной величиной. К примеру, итератор, отстоящий на 4 шага итератора от заданного итератора p может быть получен как prior(p, 4).

Функции создал Dave Abrahams. Версии с двумя аргументами создал Daniel Walker.

 

Класс noncopyable

Класс noncopyable является базовым. Пользовательский класс должен наследовать от noncopyable, чтобы запретить создание объектов через копирование и копирование через присваивание.

Некоторые объекты, в частности те, которые управляют сложными ресурсами (файлами или сетевыми сессиями), не поддерживают семантику копирования. Иногда семантика копирования в принципе возможна, но она имеет либо весьма ограниченную полезность, либо слишком сложна для правильной реализации. Иногда Вы разрабатываете класс, который просто не нужно копировать, и Вы не желаете тратить время на написание соответствующих функций. Наследование от noncopyable предотвращает создание компилятором по умолчанию конструктора копирования и оператора присваивания, что предотвращает других программистов от ошибочного использования класса.

Обычный способ решения проблемы заключается в объявлении приватных конструктора копирования и оператора присваивания, и затем документирования причин, по которым это сделано. Но наследование от класса noncopyable проще и очевиднее, и не тредбует дополнительного документирования.

Программа noncopyable_test.cpp может быть использована для проверки правильного функционирования класса noncopyable. Она успешно откомпилирована с помощью GCC 2.95, Metrowerks CodeWarrior 5.0, и  Microsoft Visual C++ 6.0 sp 3.

Создатель: Dave Abrahams.

Пример

// inside one of your own headers ...
#include <boost/utility.hpp>

class ResourceLadenFileSystem : boost::noncopyable {
...

Обоснование

Класс noncopyable имеет защищенные конструктор и деструктор, чтобы подчеркнуть тот факт, что он используется только как базовый класс. Dave Abrahams сделал замечание о возможном негативном влиянии на компиляторную оптимизацию кода после добавления (даже пустого) деструктора. Он заявил: "Возможно, эти опасения беспочвенны, потому что noncopyable будет использован главным образом для классов, которые управляют ресурсами и таким образом имеют нетривиальные деструкторы".

Шаблон функции addressof()

Функция addressof() возвращает адерс объекта.

template <typename T> inline T*                addressof(T& v);
template <typename T> inline const T*          addressof(const T& v);
template <typename T> inline volatile T*       addressof(volatile T& v);
template <typename T> inline const volatile T* addressof(const volatile T& v);

C++ разрешает программисту заменять унарный оператор в классе operator&() для получения адреса объекта. Получение истинного адреса объекта требует неуклюжих тюков с преобразованием (casting), чтобы избежать вызова перегруженного оператора  operator&(). Функция addressof() обеспечивает обертку для необходимого кода< чтобы упростить получение истинного адреса объекта.

Программа addressof_test.cpp может быть использована для проверки правильной работы функции addressof().

Добавил: Brad King на основе идей, возникших в дискуссии с Doug Gregor.

Пример

#include <boost/utility.hpp>

struct useless_type {};
class nonaddressable {
  useless_type operator&() const;
};

void f() {
  nonaddressable x;
  nonaddressable* xp = boost::addressof(x);
  // nonaddressable* xpe = &x; /* error */
}

P.S.: Нагло спёрто отсюда: BOOST C++: заголовочный файл boost/utility.hpp

Комментариев нет:

Отправить комментарий