Я слышал auto_ptr
, что C ++ 11 устарел. Что является причиной этого?
Также хотелось бы узнать разницу между auto_ptr
и shared_ptr
.
Ответы:
Прямая замена auto_ptr
(или, по крайней мере, самая близкая к ней) есть unique_ptr
. Что касается «проблемы», все довольно просто: auto_ptr
передает право владения, когда оно назначено. unique_ptr
также передает право собственности, но благодаря кодификации семантики перемещения и магии ссылок rvalue это может происходить значительно более естественно. Он также значительно лучше «вписывается» в остальную часть стандартной библиотеки (хотя, честно говоря, отчасти это произошло благодаря тому, что остальная часть библиотеки изменилась с учетом семантики перемещения, а не всегда требовала копирования).
Изменение имени также (ИМО) приветствуется - на auto_ptr
самом деле мало что говорит вам о том, что оно пытается автоматизировать, тогда unique_ptr
как это довольно разумное (если краткое) описание того, что предоставляется.
auto_ptr
название: auto предлагает автоматический, как в автоматической переменной, и относится к одной вещи, которая auto_ptr
делает: уничтожает управляемый ресурс в его деструкторе (когда он выходит за пределы области видимости).
auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
std::sort
не имеет специализации unique_ptr
. Вместо этого было изменено указание никогда не копировать. Так на auto_ptr
самом деле делает работу с современным sort
. Но C ++ 98/03 sort
является здесь просто примером алгоритма: любой общий алгоритм (предоставленный стандартным или написанным пользователем), который предполагает, что синтаксис копирования имеет семантику копирования, вероятно, будет иметь ошибку времени выполнения, если используется с auto_ptr
, потому что перемещаетсяauto_ptr
незаметно с копией синтаксиса. Проблема гораздо шире, чем просто . sort
Я нашел существующие ответы отличными, но из PoV указателей. ИМО, идеальный ответ должен иметь ответ с точки зрения пользователя / программиста.
Первым делом (как указал Джерри Коффин в своем ответе)
shared_ptr: если вас беспокоит освобождение ресурса / памяти И если у вас есть несколько функций, которые могут использовать объект AT-DIFFERENT раз, тогда используйте shared_ptr.
В DIFFERENT-Times представьте себе ситуацию, когда объект-ptr хранится в нескольких структурах данных, а затем к нему осуществляется доступ. Другой пример - это, конечно, несколько потоков.
unique_ptr: если все, что вас беспокоит, - это освобождение памяти, а доступ к объекту - ПОСЛЕДОВАТЕЛЬНЫЙ, выберите unique_ptr.
Под ПОСЛЕДОВАТЕЛЬНОМ я подразумеваю, что в любой момент объект будет доступен из одного контекста. Например, объект, который был создан и использовался сразу после создания создателем. После создания объект сохраняется в ПЕРВОЙ структуре данных. Затем объект либо уничтожается после ОДНОЙ структуры данных, либо перемещается во ВТОРОЙ структуру данных.
В этой строке я буду называть общий / уникальный _ptr интеллектуальными указателями. (auto_ptr также является умным указателем, НО из-за недостатков в его конструкции, из-за которых они устарели и на которые, я думаю, я укажу в следующих строках, их не следует группировать с помощью умного указателя.)
Единственная наиболее важная причина того, почему auto_ptr устарел в пользу smart-указателя, - это семантика присваивания. Если бы не по этой причине, они бы добавили все новые полезности семантики перемещения в 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% программистов, которые намеренно хотят передать право собственности, C ++ 11 дал им std :: move (), что сделало их намерение совершенно ясным для всех стажеров, которые собираются читать и поддерживать код.)
auto_ptr
значения указывали на один и тот же объект (поскольку они не предоставляют совместного владения, первое, что умрет, оставит другое со смертельным наследием; это также верно для unique_ptr
использования), можете ли вы предложить, что было предназначено в оставшиеся 96,8584073465% всего использования?
*a=*b;
здесь только значение b копируется в a. Я надеюсь, что и a, и b по-прежнему принадлежат одним и тем же людям. Вы упомянули, что собственность будет передана. Как это будет?
auto_ptr
объекту. Присвоение / от указанной стоимости не влияет на право собственности и не имеет отношения к ней. Надеюсь, вы еще не пользуетесь auto_ptr
?
Еще один подход к объяснению разницы ....
Функционально 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
набор на a nullptr
, и проблема в том, что это может произойти слишком легко, если программист не продумал его безопасность.
Например, если у class
/ struct
есть std::auto_ptr
член, то при создании копии экземпляра будет release
указатель из копируемого экземпляра: это странная и опасно запутывающая семантика, поскольку обычно копирование чего-либо не меняет его. Автору класса / структуры легко не заметить освобождение указателя, рассуждая об инвариантах и состоянии, и, следовательно, случайно попытаться разыменовать интеллектуальный указатель, пока он равен нулю, или просто еще не ожидает доступа / владения указанными данными.
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