Я слышал, что auto_ptr
устарел в С++ 11. В чем причина этого?
Также я хотел бы узнать разницу между auto_ptr
и shared_ptr
.
Я слышал, что auto_ptr
устарел в С++ 11. В чем причина этого?
Также я хотел бы узнать разницу между auto_ptr
и shared_ptr
.
Прямая замена auto_ptr
(или самое близкое к одному в любом случае) unique_ptr
. Что касается "проблемы", это довольно просто: auto_ptr
передает право собственности, когда оно назначено. unique_ptr
также передает право собственности, но благодаря кодификации семантики перемещения и магии ссылок rvalue она может сделать это значительно более естественно. Он также "подходит" к остальной части стандартной библиотеки значительно лучше (хотя, справедливости ради, некоторые из них - благодаря остальной библиотеке, изменяющейся для размещения семантики перемещения, а не всегда требующей копирования).
Изменение имени также (IMO) приветствуется - auto_ptr
действительно не говорит вам о том, что он пытается автоматизировать, тогда как unique_ptr
является довольно разумным (если краткое) описанием того, что предусмотрено.
Я нашел существующие ответы великолепными, но из PoV указателей. ИМО, идеальный ответ должен иметь перспективный ответ пользователя/программиста.
Первое, что сначала (как указал Джерри Коффин в его ответе)
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
От: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Виды присвоений, поддерживаемых auto_ptr
Теперь, придя к причине, ПОЧЕМУ само копирование было так не нравится, у меня есть эта теория:
Непреднамеренное поведение действительно не нравится и, следовательно, не нравится для auto_ptr.
(Для 3.1415926536% программистов, которые намеренно хотят передать право собственности на С++ 11, дали им std:: move(), что сделало их намерение совершенно ясным для всех стажеров, которые будут читать и поддерживать код. )
shared_ptr
может храниться внутри контейнеров. auto_ptr
не может.
BTW unique_ptr
- это действительно прямая замена auto_ptr
, она объединяет лучшие функции как std::auto_ptr
, так и boost::scoped_ptr
.
Еще один объясняет разницу....
Функционально, С++ 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 или просто еще не ожидал доступа/прав доступа к указанным данным.
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