Dlaczego nie mogę wcisnąć_powrotu unikatowej_ptr do wektora?

217

Co jest nie tak z tym programem?

#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;
}

Błąd:

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
użytkownik383352
źródło

Odpowiedzi:

328

Musisz przenieść unique_ptr:

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

unique_ptrgwarantuje, że pojedynczy unique_ptrpojemnik jest własnością trzymanego wskaźnika. Oznacza to, że nie możesz tworzyć kopii unique_ptr(ponieważ wtedy dwie unique_ptrposiadałyby własność), więc możesz tylko przenieść.

Pamiętaj jednak, że twoje obecne użycie unique_ptrjest nieprawidłowe. Nie można go używać do zarządzania wskaźnikiem do zmiennej lokalnej. Żywotność zmiennej lokalnej jest zarządzana automatycznie: zmienne lokalne są niszczone po zakończeniu bloku (np. Gdy funkcja powraca, w tym przypadku). Musisz dynamicznie przydzielić obiekt:

std::unique_ptr<int> ptr(new int(1));
James McNellis
źródło
12
Ponieważ nie może być tylko jeden, trzeba również być w stanie przekazać tymczasowy bezpośrednio do wektora: vec.push_back(std::unique_ptr<int>(new int(1)));. unique_ptrmożna również użyć niestandardowego narzędzia usuwającego (który nic nie robi), ale należy wziąć pod uwagę, że adres zmiennej lokalnej staje się nieprawidłowy na końcu zakresu.
UncleBens,
18
Inną opcją jest użycie emplace_back. np.vec.emplace_back(new int(1));
deft_code
75
@deft_code: Nie, to nie jest bezpieczne. emplace_backOperacja może rzucać, a jeśli tak, to dynamicznie przydzielane intbędzie przeciekał. Ogólna zasada jest taka, że ​​wszystkie dynamiczne alokacje powinny należeć do nazwanego inteligentnego wskaźnika, aby uniknąć nieszczelności.
James McNellis,
8
Metoda make_shared () zwraca parametr shared_ptr, a nie unikalny_ptr. Niestety w C ++ 11 nie ma make_unique (); niefortunne pominięcie, które, mam nadzieję, zostanie naprawione w C ++ 14
cdmh 14.04.13
29
@FKaria make_unique () oznaczałoby, że newnigdy nie trzeba wywoływać bezpośrednio, co zmienia sposób myślenia programisty i pozwala uniknąć (znacznie zmniejsza) wycieki pamięci. Porady takie jak „Unikaj nowych i usuń” mogą pojawić się w następnym wydaniu książki Meyers / Alexandrescu / Sutter :)
cdmh
24

std :: unique_ptr nie ma konstruktora kopiowania. Tworzysz instancję, a następnie poprosisz std :: vector o skopiowanie tej instancji podczas inicjalizacji.

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>]'

Klasa spełnia wymagania MoveConstructible i MoveAssignable, ale nie spełnia wymagań CopyConstructible ani CopyAssignable.

Poniższe działa z nowym dotyczą wywołań w miejscu pracy.

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

Zobacz używanie Unique_ptr ze standardowymi kontenerami bibliotecznymi do dalszego czytania.

Ben Crowhurst
źródło
5
Zobacz ten komentarz - korzystanie z emplace_x()funkcji jest niebezpieczne podczas używania inteligentnych wskaźników.
Qix - MONICA MISTREATED
Więc jaki jest najlepszy sposób na przechowywanie unikatowego pliku w wektorze? Jest bardzo powolny w porównaniu z surowym wskaźnikiem, który testowałem.
user2189731