Warum kann ich ein unique_ptr nicht in einen Vektor zurückschieben?

217

Was ist los mit diesem Programm?

#include <memory>
#include <vector>

int main()
{
    std::vector<std::unique_ptr<int>> vec;

    int x(1);
    std::unique_ptr<int> ptr2x(&x);
    vec.push_back(ptr2x); //This tiny command has a vicious error.

    return 0;
}

Der Fehler:

In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/mingw32/bits/c++allocator.h:34:0,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/allocator.h:48,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/memory:64,
                 from main.cpp:6:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = std::unique_ptr<int>, _Tp* = std::unique_ptr<int>*]':
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:745:6:   instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]'
main.cpp:16:21:   instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]'
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/ext/new_allocator.h:105:9: error: used here
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/vector:69:0,
                 from main.cpp:7:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::unique_ptr<int>&}, _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >, typename std::vector<_Tp, _Alloc>::_Base::_Tp_alloc_type::pointer = std::unique_ptr<int>*]':
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:749:4:   instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]'
main.cpp:16:21:   instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]'
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/vector.tcc:314:4: error: used here
user383352
quelle

Antworten:

328

Sie müssen Folgendes verschieben unique_ptr:

vec.push_back(std::move(ptr2x));

unique_ptrgarantiert, dass ein einzelner unique_ptrContainer Eigentümer des gehaltenen Zeigers ist. Dies bedeutet, dass Sie keine Kopien von a erstellen können unique_ptr(da dann zwei unique_ptrs Eigentümer wären), sodass Sie es nur verschieben können.

Beachten Sie jedoch, dass Ihre aktuelle Verwendung von nicht unique_ptrkorrekt ist. Sie können damit keinen Zeiger auf eine lokale Variable verwalten. Die Lebensdauer einer lokalen Variablen wird automatisch verwaltet: Lokale Variablen werden zerstört, wenn der Block endet (z. B. wenn die Funktion zurückgegeben wird, in diesem Fall). Sie müssen das Objekt dynamisch zuordnen:

std::unique_ptr<int> ptr(new int(1));
James McNellis
quelle
12
Da es nur eine geben kann, sollte man auch in der Lage sein, eine temporäre direkt an den Vektor zu übergeben : vec.push_back(std::unique_ptr<int>(new int(1)));. unique_ptrkann auch einen benutzerdefinierten Löscher verwenden (der nichts tut), aber dann muss berücksichtigt werden, dass die Adresse der lokalen Variablen am Ende des Bereichs ungültig wird.
Onkel Bens
18
Eine andere Option ist zu verwenden emplace_back. zBvec.emplace_back(new int(1));
deft_code
75
@deft_code: Nein, das ist nicht sicher. Die emplace_backOperation kann werfen, und wenn dies der Fall ist, wird die dynamisch zugewiesene intDatei durchgesickert. Als Faustregel gilt, dass alle dynamischen Zuordnungen einem benannten Smart Pointer gehören sollten, um Undichtigkeiten zu vermeiden.
James McNellis
8
make_shared () gibt einen shared_ptr zurück, keinen unique_ptr. Leider gibt es in C ++ 11 kein make_unique (); eine unglückliche Auslassung, die hoffentlich in C ++ 14
behoben wird
29
@FKaria make_unique () würde bedeuten, dass newniemals direkt aufgerufen werden muss, was die Denkweise des Programmierers ändert und Speicherlecks vermeidet (erheblich reduziert). Ratschläge wie "Neu vermeiden und löschen" können dann in der nächsten Ausgabe von Meyers / Alexandrescu / Sutters Buch erscheinen :)
cdmh
24

std :: unique_ptr hat keinen Kopierkonstruktor. Sie erstellen eine Instanz und fordern den std :: vector auf, diese Instanz während der Initialisierung zu kopieren.

error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::uniqu
e_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_D
eleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> =
 std::unique_ptr<int>]'

Die Klasse erfüllt die Anforderungen von MoveConstructible und MoveAssignable, jedoch nicht die Anforderungen von CopyConstructible oder CopyAssignable.

Das Folgende funktioniert mit den neuen Emplace- Aufrufen.

std::vector< std::unique_ptr< int > > vec;
vec.emplace_back( new int( 1984 ) );

Weitere Informationen finden Sie unter Verwenden von unique_ptr mit Standardbibliothekscontainern .

Ben Crowhurst
quelle
5
Siehe diesen Kommentar - Die Verwendung von emplace_x()Funktionen ist bei Verwendung von intelligenten Zeigern unsicher.
Qix - MONICA wurde am
Was ist der beste Weg, um ein unique_ptr in einem Vektor zu speichern? Es ist extrem langsam im Vergleich zu rohen Zeigern, wie ich getestet habe.
user2189731