Чому auto_ptr не підтримується?


Відповіді:


91

Пряма заміна auto_ptr(або найближче до одного в будь-якому випадку) є unique_ptr. Що стосується "проблеми", вона досить проста: auto_ptrпередає право власності, коли їй призначено.unique_ptrтакож передає право власності, але завдяки кодифікації семантики переміщення та магії посилань rvalue він може зробити це значно більш природно. Він також набагато краще "відповідає" решті стандартної бібліотеки (хоча, справедливості заради, деякі з них завдяки зміні решти бібліотеки з урахуванням семантики переміщення замість того, щоб завжди вимагати копіювання).

Зміна назви також є вітальною (IMO) - auto_ptrнасправді не говорить вам багато про те, що вона намагається автоматизувати, тоді як unique_ptrє досить розумним (якщо стислим) описом того, що пропонується.


24
Просто примітка щодо auto_ptrназви: auto пропонує автоматичну, як і в автоматичній змінній, і вона стосується одного, що auto_ptrробить: знищення керованого ресурсу в його деструкторі (коли воно виходить за межі сфери дії).
Вінченцо Пій

13
Додаткова інформація: Ось офіційне обґрунтування припинення дії auto_ptr: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
Говард Хіннант,

@HowardHinnant цікавий документ! дивно в тому сенсі, що якщо std :: sort () is має спеціалізацію для std :: unique_ptr використовувати семантику переміщення за необхідності. Цікаво, чому std :: sort () не може бути спеціалізованим для std :: auto_ptr, щоб виправити проблему копіювання, згадану в документі. Заздалегідь спасибі.
Хей

2
@Hei: std::sortне має спеціалізації для unique_ptr. Натомість було повторно вказано ніколи не копіювати. Так на auto_ptrсамому ділі робить роботу з сучасним sort. Але C ++ 98/03 sortтут лише приклад алгоритму: Будь-який загальний алгоритм (наданий std або написаний користувачем), який припускає, що синтаксис копії має семантику копіювання, швидше за все, матиме помилку під час виконання auto_ptr, оскільки auto_ptrтихо рухається з синтаксисом копіювання . Питання набагато ширше, ніж просто sort.
Говард Хіннант

35

Я знайшов існуючі відповіді чудовими, але з точки зору показників. ІМО, ідеальною відповіддю має бути перспективна відповідь користувача / програміста.

Перш за все (як зазначив Джеррі Коффін у своїй відповіді)

  • auto_ptr може бути замінений на shared_ptr або unique_ptr залежно від ситуації

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

  • призначення переміщення (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 (), що зробило їхній намір кристально зрозумілим для всіх стажерів, які збираються читати та підтримувати код.)


1
Оскільки ви ніколи не хочете, щоб два auto_ptrзначення вказували на один і той самий об'єкт (оскільки вони не надають спільне право власності, перше, що помре, залишить інше смертельною спадщиною; це також стосується unique_ptrвикористання), чи можете ви запропонувати, що було задумано в ті, що залишились 96,8584073465% від усього використання?
Марк ван Левен

Не можу говорити за всіх, але, я гадаю, вони вважають, що право власності на об’єкт переміщується, а НЕ просто дублюється, що є помилковим.
Ajeet Ganga

@AjeetGanga У наступній фразі "the little- * (передбачена каламбур)", яку ви згадали як "каламбур". Ця фраза є новою для мене, і я так чи інакше погуглив її і дізнався, що тут є якийсь жарт, який цілеспрямовано зробили. Що це за жарт тут? Просто цікаво це знати.
VINOTH ENERGETIC

@AjeetGanga Ви згадали, як "маленьке- * (передбачено каламбур), пункт auto_ptr, який читають не всі програмісти, дозволяє, присвоєння одного auto_ptr іншому та передає право власності". Скажімо, у мене є два автоматичних ptr як a та b до цілого числа. Я виконую призначення, оскільки *a=*b;тут лише значення b копіюється в a. Я сподіваюся, що права власності як на “а”, так і “на“ все ще є у тих самих людей. Ви згадали, що право власності буде передано. Як це буде?
VINOTH ENERGETIC

@VINOTHENERGETIC Ajeet говорив про присвоєння auto_ptrсамому об'єкту. Присвоєння / вказівка ​​вартості не впливає і не стосується власності. Сподіваюся, ви все ще не використовуєте auto_ptr?
underscore_d

23

shared_ptrможна зберігати всередині контейнерів. auto_ptrне може.

ДО РЕЧІ unique_ptrдійсно пряма auto_ptrзаміна, він поєднує в собі кращі риси обох std::auto_ptrі boost::scoped_ptr.


11

Ще один погляд на пояснення різниці ....

Функціонально 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 тихо "краде" право власності +1
camino

3

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.