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

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));

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.