C++ 3d.Комментарии

auto_ptr


В стандартном заголовочном файле <memory> auto_ptr объявлен следующим образом...

Ввиду того, что после выхода первых (английских) тиражей стандарт претерпел некоторые изменения в части auto_ptr, концовку данного раздела следует заменить следующим текстом (он взят из списка авторских исправлений к 4 тиражу).

Для достижения данной семантики владения (также называемой семантикой разрушающего копирования (destructive copy semantics)), семантика копирования шаблона auto_ptr радикально отличается от семантики копирования обычных указателей: когда один auto_ptr копируется или присваивается другому, исходный auto_ptr очищается (эквивалентно присваиванию 0 указателю). Т.к. копирование auto_ptr приводит к его изменению, то const auto_ptr не может быть скопирован.

Шаблон auto_ptr определен в <memory> следующим образом: template<class X> class std::auto_ptr { // вспомогательный класс template <class Y> struct auto_ptr_ref { /* ... */ };

X* ptr; public: typedef X element_type;

explicit auto_ptr(X* p =0) throw() { ptr=p; } ~auto_ptr() throw() { delete ptr; }

// обратите внимание: конструкторы копирования и операторы // присваивания имеют неконстантные аргументы

// скопировать, потом a.ptr=0 auto_ptr(auto_ptr& a) throw();

// скопировать, потом a.ptr=0 template<class Y> auto_ptr(auto_ptr<Y>& a) throw();

// скопировать, потом a.ptr=0 auto_ptr& operator=(auto_ptr& a) throw();

// скопировать, потом a.ptr=0 template<class Y> auto_ptr& operator=(auto_ptr<Y>& a) throw();

X& operator*() const throw() { return *ptr; } X* operator->() const throw() { return ptr; }

// вернуть указатель X* get() const throw() { return ptr; }



// передать владение X* release() throw() { X* t = ptr; ptr=0; return t; }

void reset(X* p =0) throw() { if (p!=ptr) { delete ptr; ptr=p; } }

// скопировать из auto_ptr_ref auto_ptr(auto_ptr_ref<X>) throw();

// скопировать в auto_ptr_ref template<class Y> operator auto_ptr_ref<Y>() throw();


// разрушающее копирование из auto_ptr template<class Y> operator auto_ptr<Y>() throw(); };

Назначение auto_ptr_ref -- обеспечить семантику разрушающего копирования, ввиду чего копирование константного auto_ptr становится невозможным. Конструктор-шаблон и оператор присваивания-шаблон обеспечивают возможность неявного пребразования auto_ptr<D> в auto_ptr<B> если D* может быть преобразован в B*, например: void g(Circle* pc) { auto_ptr<Circle> p2 = pc; // сейчас p2 отвечает за удаление

auto_ptr<Circle> p3 = p2; // сейчас p3 отвечает за удаление, // а p2 уже нет

p2->m = 7; // ошибка программиста: p2.get()==0

Shape* ps = p3.get(); // извлечение указателя

auto_ptr<Shape> aps = p3; // передача прав собственности и // преобразование типа

auto_ptr<Circle> p4 = pc; // ошибка: теперь p4 также отвечает за удаление }

Эффект от использования нескольких auto_ptr для одного и того же объекта неопределен; в большинстве случаев объект будет уничтожен дважды, что приведет к разрушительным результатам.

Следует отметить, что семантика разрушающего копирования не удовлетворяет требованиям к элементам стандартных контейнеров или стандартных алгоритмов, таких как sort(). Например: // опасно: использование auto_ptr в контейнере void h(vector<auto_ptr<Shape> >& v) { sort(v.begin(),v.end()); // не делайте так: элементы не будут отсортированы }

Понятно, что auto_ptr не является обычным "умным" указателем, однако он прекрасно справляется с предоставленной ему ролью -- обеспечивать безопасную относительно исключений работу с автоматическими указателями, и делать это без существенных накладных расходов.


Содержание раздела