2010-07-19 8 views
145

Was ist falsch an diesem Programm?Warum kann ich ein unique_ptr nicht in einen Vektor push_back?

#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:

$ g++ -std=gnu++0x main.cpp 
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: I 
n 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:74 
5:6: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(con 
st value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::alloca 
tor<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:20 
7:7: 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>]' 
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: I 
n member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::v 
ector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::u 
nique_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::p 
ointer = std::unique_ptr<int>*]': 
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:74 
9:4: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(con 
st value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::alloca 
tor<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:20 
7:7: 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>]' 
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/vector.tcc:314: 
4: error: used here 

Antwort

238

Sie müssen die unique_ptr bewegen:

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

unique_ptr garantiert, dass ein einzelner unique_ptr Container Eigentum des gehaltenen Zeiger hat. Dies bedeutet, dass Sie keine Kopien einer unique_ptr erstellen können (weil dann zwei unique_ptr s Eigentümerschaft haben), so dass Sie es nur verschieben können.

Beachten Sie jedoch, dass Ihre aktuelle Verwendung von unique_ptr nicht korrekt 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 in diesem Fall zurückkehrt). Sie müssen das Objekt dynamisch zuweisen:

std::unique_ptr<int> ptr(new int(1)); 
+11

Da es nur einen geben kann, sollte man auch ein temporäres direkt an den Vektor übergeben können: 'vec.push_back (std :: unique_ptr (new int (1)));'. 'unique_ptr' kann auch einen benutzerdefinierten Deleter verwenden (der nichts tut), aber dann muss man berücksichtigen, dass die Adresse der lokalen Variablen am Ende des Bereichs ungültig wird. – UncleBens

+17

Eine weitere Option ist die Verwendung von 'emplace_back'. z.B. 'vec.emplace_back (new int (1));' –

+60

@ deft_code: Nein, das ist nicht sicher. Die 'emplace_back'-Operation kann auslösen, und wenn dies der Fall ist, wird das dynamisch zugewiesene' int' durchgelassen. Als Faustregel gilt, dass alle dynamischen Zuordnungen einem benannten Smart-Pointer gehören sollten, um Undichtigkeiten zu vermeiden. –

15

std::unique_ptr hat keinen Kopierkonstruktor. Sie erstellen eine Instanz und bitten dann die std::vector, 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>]' 

The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.

Folgende Arbeiten mit den neuen emplace Anrufe.

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

Weitere Informationen finden Sie unter using unique_ptr with standard library containers.

+1

Siehe [diesen Kommentar] (https://stackoverflow.com/questions/3283778/why-cani-i-not -pushback-a-unique-ptr-in-a-vector # comment11813799_3283795) - Verwendung von 'emplace_x()' Funktionen sind unsicher, wenn Sie Smartpointer verwenden. – Qix

Verwandte Themen