Класс auto_ptr. Предупреждение

   
На этом шаге мы рассмотрим особенности передачи прав владения объектом.

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

// ПЛОХОЙ ПРИМЕР
template <class T>
void bad_print (std::auto_ptr <T> p)     // p становится владельцем
                                         // переданного аргумента
{
  // Указывает ли р на объект?
  if (p.get() == NULL) 
  { 
    std::cout << "NULL";
  } 
  else 
  {
    std::cout << *p;
  }
}    // Ошибка - обьект, на который ссылается р,
     // удаляется при выходе из функции.

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

std::auto_ptr <int> p(new int);
*p = 42;       // Изменение значения, на которое ссылается р 
bad_print(p);  // Удаление данных, на которые ссылается р 
*р = 18;       // ОШИБКА ВРЕМЕНИ ВЫПОЛНЕНИЯ

   
Может, стоит передавать auto_ptr по ссылке? Однако передача auto_ptr по ссылке противоречит концепции владения.
Нельзя быть полностью уверенным в том, что функция, получающая auto_ptr по ссылке, передаст (или не передаст) право
владения. Передача auto_ptr по ссылке - очень плохое решение, никогда не используйте его в своих программах.

   
В соответствии с концепцией auto_ptr право владения может передаваться функции при помощи константной ссылки. Но
такое решение очень опасно, поскольку программисты обычно полагают, что объект, передаваемый по константной ссылке, остается
неизменным. К счастью, на поздней стадии проектирования было принято решение, которое сделало применение auto_ptr менее
рискованным. Благодаря каким-то ухищрениям реализации передача права владения с константными ссылками стала невозможной.
Более того, право владения для констант auto_ptr вообще не изменяется:

const std::auto_ptr <int> p(new int);
*p = 42;       // Изменение значения, на которое ссылается р
bad_print(p);  // ОШИБКА КОМПИЛЯЦИИ
*р = 18;       // ОК

   
Такое решение повышает надежность auto_ptr. Многие интерфейсы используют константные ссылки для получения данных,
которые проходят внутреннее копирование. Собственно говоря, все контейнерные классы стандартной библиотеки C++ ведут
себя подобным образом:

template <class T>
void container::insert (const T& value)
{
  .    .    .    .
  x = value;  // Внутреннее копирование
  .    .    .    .
}

   
Если бы такое присваивание было возможно для auto_ptr, то операция присваивания передала бы право владения контейнеру.
Но из-за реальной архитектуры auto_ptr этот вызов приводит к ошибке на стадии компиляции:

контейнер <std:auto_ptr<int> > с; 
const std::auto_ptr<int> p(new int);
.    .    .    .
c.insert(p):  // ОШИБКА
.    .    .    .

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

   
Константность не означает неизменности объекта, принадлежащего auto_ptr. Вы не сможете изменить право владения для
константного экземпляра auto_ptr, однако ничто не мешает изменить значение, на которое он ссылается. Пример:

std::auto_ptr<int> f()
{
  const std::auto_ptr<int> p(new int); // Право владения не передается 
  std::auto_ptr<int> q(new int);     // Право владения передается
  *p = 42;  // OK: изменение значения, на которое ссылается р
  bad_print(p);  // ОШИБКА КОМПИЛЯЦИИ
  *р = *q; // OK; изменение значения, на которое ссылается р
  р = q;  // ОШИБКА КОМПИЛЯЦИИ
  return p;  // ОШИБКА КОМПИЛЯЦИИ
}

   
Если const auto_ptr передается или возвращается в аргументе, любая попытка присвоить новый объект приводит к ошибке
компиляции. В отношении константности const auto_ptr ведет себя как константный указатель (Т* const p), а не как
указатель на константу (const T* р), хотя синтаксис вроде бы говорит об обратном.

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



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

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