Почему auto_ptr считается устаревшим? - PullRequest
82 голосов
/ 13 сентября 2010

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

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

Ответы [ 5 ]

84 голосов
/ 13 сентября 2010

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

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

32 голосов
/ 24 февраля 2013

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

Перво-наперво (как указал Джерри Коффин в своем ответе)

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

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

По DIFFERENT-Times, представьте себе ситуацию, когда object-ptr хранится в нескольких структурах данных и к ним позже обращаются.Несколько потоков, конечно, еще один пример.

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

Под ПОСЛЕДОВАТЕЛЬНЫМ, я имею в виду, в любой момент объект будет доступен из одного контекста.Например, объект, который был создан и использовался сразу после создания создателем.После создания объект сохраняется в FIRST структуре данных.Затем либо объект уничтожается после ОДНОЙ структуры данных, либо перемещается в SECOND структуру данных.

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

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

По ссылке: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

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

  • назначение перемещения (1)
  • назначение нулевого указателя (2)
  • назначение приведения типа (3)
  • копирование назначения (удалено!) (4)

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

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

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

Теперь рассмотрим причину, по которой само назначение копии было настолько неприязненным, у меня есть такая теория:

  1. Не все программисты читают книги или стандарты
  2. auto_ptr на первый взгляд, обещает вам владение объектом
  3. little- * (каламбур предназначен), пункт auto_ptr,который не читается всеми программистами, разрешает присваивать один auto_ptr другому и передает право собственности.
  4. Исследования показали, что это поведение предназначено для 3,1415926535% всего использования и непреднамеренно в других случаях.

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

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

21 голосов
/ 13 сентября 2010

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

КСТАТИ unique_ptr действительно прямая замена auto_ptr, она сочетает в себе лучшие функции std::auto_ptr и boost::scoped_ptr.

11 голосов
/ 12 февраля 2015

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

Функционально, C ++ 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, и проблема в том, что это может произойти слишком легко, без программистапродумав его безопасность.

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

3 голосов
/ 11 июля 2016

auto_ptr нельзя использовать в контейнерах STL, поскольку он имеет конструктор копирования, который не соответствует требованиям контейнера CopyConstructible . 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
...