Я чув auto_ptr
, що його застаріло в C ++ 11. У чому причина цього?
Також я хотів би знати різницю між auto_ptr
і shared_ptr
.
Відповіді:
Пряма заміна auto_ptr
(або найближче до одного в будь-якому випадку) є unique_ptr
. Що стосується "проблеми", вона досить проста: auto_ptr
передає право власності, коли їй призначено.unique_ptr
також передає право власності, але завдяки кодифікації семантики переміщення та магії посилань rvalue він може зробити це значно більш природно. Він також набагато краще "відповідає" решті стандартної бібліотеки (хоча, справедливості заради, деякі з них завдяки зміні решти бібліотеки з урахуванням семантики переміщення замість того, щоб завжди вимагати копіювання).
Зміна назви також є вітальною (IMO) - 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
тут лише приклад алгоритму: Будь-який загальний алгоритм (наданий std або написаний користувачем), який припускає, що синтаксис копії має семантику копіювання, швидше за все, матиме помилку під час виконання auto_ptr
, оскільки auto_ptr
тихо рухається з синтаксисом копіювання . Питання набагато ширше, ніж просто sort
.
Я знайшов існуючі відповіді чудовими, але з точки зору показників. ІМО, ідеальною відповіддю має бути перспективна відповідь користувача / програміста.
Перш за все (як зазначив Джеррі Коффін у своїй відповіді)
shared_ptr: Якщо ви стурбовані звільненням ресурсу / пам'яті І якщо у вас є більше ніж одна функція, яка може використовувати об'єкт AT-РІЗНИЙ раз, тоді перейдіть до shared_ptr.
За допомогою DIFFERENT-Times, подумайте про ситуацію, коли об’єкт-ptr зберігається в декількох структурах даних і надалі здійснюється доступ до нього. Кілька потоків, звичайно, ще один приклад.
unique_ptr: Якщо все, що вас турбує, це звільнення пам'яті, а доступ до об'єкта ПОСЛІДОВНИЙ, перейдіть до unique_ptr.
Послідовно, я маю на увазі, що в будь-який момент об’єкт буде доступний з одного контексту. Наприклад, об’єкт, який був створений і використаний відразу після створення творцем. Після створення об'єкт зберігається в ПЕРШІЙ структурі даних. Потім або об’єкт руйнується після ОДНОЇ структури даних, або переміщується до ДРУГОЇ структури даних.
З цього рядка я буду називати спільний / унікальний _ptr смарт-покажчиками. (auto_ptr також є розумним покажчиком, АЛЕ через недоліки в його дизайні, для яких вони застаріли, і на які, я думаю, я вкажу в наступних рядках, їх не слід групувати за допомогою смарт-покажчика.)
Однією з найважливіших причин того, чому auto_ptr було припинено на користь смарт-покажчика, є семантика assignment. Якби не з цієї причини, вони додали б усі нові смаки переміщення семантики до 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. Я сподіваюся, що права власності як на “а”, так і “на“ все ще є у тих самих людей. Ви згадали, що право власності буде передано. Як це буде?
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
встановленим значенням "а" 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