Почему auto_ptr устарел?

Я слышал, что auto_ptr устарел в С++ 11. В чем причина этого?

Также я хотел бы узнать разницу между auto_ptr и shared_ptr.

Ответ 1

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

Изменение имени также (IMO) приветствуется - auto_ptr действительно не говорит вам о том, что он пытается автоматизировать, тогда как unique_ptr является довольно разумным (если краткое) описанием того, что предусмотрено.

Ответ 2

Я нашел существующие ответы великолепными, но из PoV указателей. ИМО, идеальный ответ должен иметь перспективный ответ пользователя/программиста.

Первое, что сначала (как указал Джерри Коффин в его ответе)

  • auto_ptr может быть заменен shared_ptr или unique_ptr в зависимости от ситуации

shared_ptr: Если вы обеспокоены освобождением ресурса/памяти И если у вас есть несколько функций, которые могут использовать объект AT-DIFFERENT раз, перейдите с shared_ptr.

DIFFERENT-Times, подумайте о ситуации, когда объект-ptr хранится в нескольких структурах данных и позже доступен. Другими примерами являются несколько потоков.

unique_ptr: Если все, что вас беспокоит, освобождает память, а доступ к объекту SEQUENTIAL, затем перейдите к unique_ptr.

По SEQUENTIAL, я имею в виду, что в любой момент объект будет доступен из одного контекста. Например. объект, который был создан и использован сразу после создания создателем. После создания объект хранится в FIRST-структуре данных. Затем либо объект уничтожается после ONE-структуры данных, либо перемещается в SECOND-структуру данных.

В этой строке я буду ссылаться на общий/уникальный _ptr как на интеллектуальные указатели. (auto_ptr также является интеллектуальным указателем, но из-за недостатков в его дизайне, для которых они устарели, и которые, я думаю, укажу в следующих строках, их не следует группировать с помощью смарт-указателя.)

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

Из ссылки: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Виды присвоений, поддерживаемых unqiue_ptr

  • переместить назначение (1)
  • назначить нулевой указатель (2)
  • назначение типа-cast (3)
  • назначение копии (удалено!) (4)

От: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

Виды присвоений, поддерживаемых auto_ptr

  • назначение копии (4) виновник

Теперь, придя к причине, ПОЧЕМУ само копирование было так не нравится, у меня есть эта теория:

  • Не все программисты читают книги или стандарты.
  • auto_ptr на лице, promises вы владеете объектом
  • Маленький- * (предназначенный для каламбур), пункт auto_ptr, который не читается всеми программистами, позволяет, присваивать один auto_ptr другому и передает право собственности.
  • Исследование показало, что это поведение предназначено для 3.1415926535% всего использования и непреднамеренно в других случаях.

Непреднамеренное поведение действительно не нравится и, следовательно, не нравится для auto_ptr.

(Для 3.1415926536% программистов, которые намеренно хотят передать право собственности на С++ 11, дали им std:: move(), что сделало их намерение совершенно ясным для всех стажеров, которые будут читать и поддерживать код. )

Ответ 3

shared_ptr может храниться внутри контейнеров. auto_ptr не может.

BTW unique_ptr - это действительно прямая замена auto_ptr, она объединяет лучшие функции как std::auto_ptr, так и boost::scoped_ptr.

Ответ 4

Еще один объясняет разницу....

Функционально, С++ 11 std::unique_ptr является "фиксированным" std::auto_ptr: оба они подходят, когда - в любой момент времени во время выполнения - должен быть один владелец смарт-указателя для указательного объект.

Важнейшим отличием является создание копии или присвоение от другого интеллектуального указателя без истечения срока действия, показанного на строках => ниже:

   std::auto_ptr<T> ap(...);
   std::auto_ptr<T> ap2(get_ap_to_T());   // take expiring ownership
=> std::auto_ptr<T> ap3(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... can still try to use ap, expecting it to be non-NULL

   std::unique_ptr<T> up(...);
   std::unique_ptr<T> up2(get_up_to_T());   // take expiring ownership
=> std::unique_ptr<T> up3(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release());   // EXPLICIT code allowed

Выше, ap3 спокойно "крадет" собственность *ap, оставляя ap установленным на nullptr, и проблема в том, что это может произойти слишком легко, без того, чтобы программист продумал свою безопасность.

Например, если a class/struct имеет член std::auto_ptr, то при копировании экземпляра будет release указатель из копируемого экземпляра: эта странная и опасно запутанная семантика, как обычно, копирование что-то не меняет. Легко для автора class/struct игнорировать освобождение указателя при рассуждении об инвариантах и ​​состоянии и, следовательно, случайно попытаться разыменовать смарт-указатель в то время как null или просто еще не ожидал доступа/прав доступа к указанным данным.

Ответ 5

auto_ptr не может использоваться в контейнерах STL, потому что у него есть конструктор копирования, который не отвечает требованиям контейнера copyconstructable. unique_ptr не реализует конструктор копирования, поэтому контейнеры используют альтернативные методы. unique_ptr может использоваться в контейнерах и быстрее для std-алгоритмов, чем shared_ptr.

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3