Mengapa saya tidak bisa push_back a unique_ptr ke vektor?

217

Apa yang salah dengan program ini?

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

Kesalahan:

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
pengguna383352
sumber

Jawaban:

328

Anda harus memindahkan unique_ptr:

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

unique_ptrmenjamin bahwa satu unique_ptrwadah memiliki kepemilikan penunjuk yang ditahan. Ini berarti bahwa Anda tidak dapat membuat salinan dari unique_ptr(karena dua orang unique_ptrakan memiliki kepemilikan), jadi Anda hanya dapat memindahkannya.

Perhatikan, bagaimanapun, bahwa penggunaan Anda saat unique_ptrini tidak benar. Anda tidak dapat menggunakannya untuk mengelola pointer ke variabel lokal. Masa hidup variabel lokal dikelola secara otomatis: variabel lokal dihancurkan ketika blok berakhir (misalnya, ketika fungsi kembali, dalam kasus ini). Anda perlu mengalokasikan objek secara dinamis:

std::unique_ptr<int> ptr(new int(1));
James McNellis
sumber
12
Karena hanya ada satu, satu juga harus mampu melewati sementara langsung ke vektor: vec.push_back(std::unique_ptr<int>(new int(1)));. unique_ptrjuga dapat menggunakan deleter khusus (yang tidak melakukan apa-apa), tetapi kemudian seseorang harus memperhitungkan bahwa alamat variabel lokal menjadi tidak valid di akhir cakupan.
UncleBens
18
Pilihan lain adalah menggunakan emplace_back. misvec.emplace_back(new int(1));
deft_code
75
@deft_code: Tidak, itu tidak aman. The emplace_backoperasi dapat membuang, dan jika tidak, yang dialokasikan secara dinamis intakan bocor. Aturan praktisnya adalah bahwa semua alokasi dinamis harus dimiliki oleh penunjuk pintar bernama untuk menghindari kebocoran.
James McNellis
8
make_shared () mengembalikan shared_ptr, bukan unique_ptr. Sayangnya, tidak ada make_unique () di C ++ 11; kelalaian malang yang diharapkan akan diperbaiki di C ++ 14
cdmh
29
@FKaria make_unique () akan berarti bahwa newtidak perlu dipanggil secara langsung, yang mengubah pola pikir programmer dan menghindari (secara signifikan mengurangi) kebocoran memori. Nasihat seperti "Hindari baru dan hapus" kemudian dapat muncul dalam edisi berikutnya buku Meyers / Alexandrescu / Sutter :)
cdmh
24

std :: unique_ptr tidak memiliki copy constructor. Anda membuat sebuah instance dan kemudian meminta std :: vector untuk menyalin instance itu selama inisialisasi.

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

Kelas memenuhi persyaratan MoveConstructible dan MoveAssignable, tetapi bukan persyaratan CopyConstructible atau CopyAssignable.

Berikut ini berfungsi dengan emplace panggilan baru.

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

Lihat menggunakan unique_ptr dengan wadah perpustakaan standar untuk bacaan lebih lanjut.

Ben Crowhurst
sumber
5
Lihat komentar ini - menggunakan emplace_x()fungsi tidak aman saat menggunakan pointer pintar.
Qix - MONICA DISEBUTKAN
Jadi apa cara terbaik untuk menyimpan unique_ptr ke vektor? Ini sangat lambat dibandingkan dengan pointer mentah saat saya uji.
user2189731