Почему автоматический ptr является устаревшим?


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

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

5 78

5 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • копировать назначение (4)виновником

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

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

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

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

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

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

еще один взгляд на объяснение разницы....

функционально, C++11's 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 указатель из копируемого экземпляра: это странно и опасно запутывает семантику, поскольку обычно копирование чего-то не изменяет ее. Автору класса / структуры легко пропустить выпуск указатель при рассуждении об инвариантах и состоянии, и, следовательно, случайно пытается разыменовать смарт-указатель в то время как null, или просто еще не ожидал доступа/владения указанными данными.

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