std :: auto_ptr na std :: unique_ptr

185

Wraz z nadejściem nowego standardu (i części już dostępnych w niektórych kompilatorach) nowy typ std::unique_ptrma być zamiennikiem std::auto_ptr.

Czy ich użycie dokładnie się pokrywa (więc mogę dokonać globalnego wyszukiwania / zamiany w moim kodzie (nie żebym to zrobił, ale gdybym to zrobił)), czy powinienem być świadomy pewnych różnic, które nie są oczywiste po przeczytaniu dokumentacji?

Również jeśli jest to bezpośredni zamiennik, dlaczego nadać mu nową nazwę, a nie tylko poprawić std::auto_ptr?

Martin York
źródło

Odpowiedzi:

219

Nie można wykonać globalnego wyszukiwania / zamiany, ponieważ można skopiować auto_ptr(ze znanymi konsekwencjami), ale unique_ptrmożna tylko przenieść. Wszystko, co wygląda

std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; 

będzie musiał stać się przynajmniej tak

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);

Podobnie jak w przypadku innych różnic, unique_ptrmoże poprawnie obsługiwać tablice (zadzwoni delete[], a auto_ptrspróbuje zadzwonić delete.

Cubbi
źródło
101
z drugiej strony, wykonanie tej operacji znajdź / zamień spowoduje tylko błędy kompilacji, nie spowoduje to dyskretnego uszkodzenia kodu, o ile widzę. Tak to jest bezpieczne, jeśli ręcznie naprawić błędy kompilacji potem
jalf
7
@jalf: Rzeczywiście, nie mogę wymyślić kontrprzykładu, który byłby dobrze zdefiniowany za pomocą auto_ptrs i UB z unique_ptrs.
Cubbi,
1
więc wygląda na to, że unique_ptr to rozszerzenie auto_ptr: obsługa tablicy i usuwanie niejednoznaczności
Baiyan Huang
92

std::auto_ptri std::unique_ptrw niektórych przypadkach są niekompatybilne, aw innych spadek. Zatem żadne wyszukiwanie / zamiana nie jest wystarczająco dobre. Jednak po znalezieniu / zamianie podczas pracy z błędami kompilacji należy naprawić wszystko oprócz dziwnych przypadków narożnych. Większość błędów kompilacji będzie wymagać dodania std::move.

  • Zmienna zakresu funkcji: w
    100% kompatybilna, o ile nie przekazujesz jej wartości do innej funkcji.
  • Typ zwrotu:
    niezgodny w 100%, ale zgodny w 99% nie wydaje się błędny.
  • Parametr funkcji według wartości: w
    100% zgodny z jednym zastrzeżeniem, unique_ptrs musi zostać przekazany przez std::movewywołanie. Ten jest prosty, ponieważ kompilator narzeka, jeśli nie zrobisz tego dobrze.
  • Parametr funkcji przez odniesienie:
    100% kompatybilny.
  • Zmienna członka klasy:
    ta jest trudna. std::auto_ptrsemantyka kopiowania jest zła. Jeśli klasa nie zezwala na kopiowanie, std::unique_ptroznacza to spadek w zastępstwie. Jeśli jednak spróbujesz nadać klasie rozsądną semantykę kopiowania, musisz zmienić std::auto_ptrkod obsługi. Jest to proste, ponieważ kompilator narzeka, jeśli nie zrobisz tego dobrze. Jeśli zezwoliłeś na kopiowanie zajęć z std::auto_ptrczłonkiem bez specjalnego kodu, wstydź się i powodzenia.

Podsumowując, std::unique_ptrjest nieprzerwany std::auto_ptr. Nie zezwala w czasie kompilacji zachowań, które często były błędne podczas korzystania z std::auto_ptr. Więc jeśli używałeś go std::auto_ptrz należytą starannością, przejście na std::unique_ptrpowinno być proste. Jeśli polegałeś na std::auto_ptrdziwnym zachowaniu, musisz zrefakturować swój kod.

deft_code
źródło
8
+1 za „i tak musisz zmienić kod”. auto_ptrs są dobre tylko dla tego, co mówi 20.4.5 / 3, że są dobre.
Cubbi,
8
Pozwólcie, że dodam do tego, że należy całkowicie zastąpić auto_ptr unikalnym w swoim kodzie i naprawić błędy kompilacji. Byłbyś zaskoczony, jak wiele błędów to odkryje.
Bartosz Milewski
36

AFAIK, unique_ptrnie jest bezpośrednim zamiennikiem. Główną wadą, którą naprawia, jest ukryte przeniesienie własności.

std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership

std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly

Z drugiej strony unique_ptrbędą miały zupełnie nowe możliwości: można je przechowywać w pojemnikach.

Wujek Ben
źródło
8
Scott Meyers wspomniał również w swoim „Skutecznym C ++” (wydanie trzecie) pozycja 13 (strona 64), że kontenery STL wymagają, aby ich zawartość wykazywała „normalne” zachowanie podczas kopiowania, dlatego kontenery auto_ptrnie są dozwolone.
Qiang Xu
31

Herb Sutter ma ładne wyjaśnienie na temat GotW # 89 :

O co chodzi z auto_ptr? auto_ptr jest najbardziej charytatywnie scharakteryzowany jako dzielna próba stworzenia unikalnego_ptr zanim C ++ miał semantykę ruchu. auto_ptr jest teraz przestarzałe i nie należy go używać w nowym kodzie.

Jeśli masz auto_ptr w istniejącej bazie kodu, kiedy masz szansę, spróbuj przeprowadzić globalne wyszukiwanie i zamień auto_ptr na unikalny_ptr; zdecydowana większość zastosowań będzie działać tak samo i może ujawnić (jako błąd czasu kompilacji) lub naprawić (po cichu) błąd lub dwa, o których nie wiedziałeś, że masz.

Innymi słowy, podczas gdy globalne wyszukiwanie i zamiana może tymczasowo „zepsuć” Twój kod, powinieneś to zrobić i tak: Naprawienie błędów kompilacji może zająć trochę czasu, ale na dłuższą metę zaoszczędzi ci dużo więcej problemów.

ValarDohaeris
źródło
Świetny link. Wielkie dzięki!
fotNelton,