ทำไมฉันไม่สามารถผลักดัน unique_ptr ไปยังเวกเตอร์ได้


217

เกิดอะไรขึ้นกับโปรแกรมนี้

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

ข้อผิดพลาด:

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

คำตอบ:


328

คุณต้องย้ายunique_ptr:

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

unique_ptrรับประกันว่าunique_ptrคอนเทนเนอร์เดียวมีกรรมสิทธิ์ในตัวชี้ที่ถือครอง ซึ่งหมายความว่าคุณไม่สามารถทำสำเนาของunique_ptr(เพราะแล้วทั้งสองunique_ptrจะมีกรรมสิทธิ์) ดังนั้นคุณสามารถย้ายได้

อย่างไรก็ตามโปรดทราบว่าการใช้งานปัจจุบันของคุณunique_ptrไม่ถูกต้อง คุณไม่สามารถใช้มันเพื่อจัดการตัวชี้ไปยังตัวแปรท้องถิ่น อายุการใช้งานของตัวแปรโลคัลถูกจัดการโดยอัตโนมัติ: ตัวแปรโลคัลถูกทำลายเมื่อบล็อกสิ้นสุด (เช่นเมื่อฟังก์ชันส่งคืนในกรณีนี้) คุณต้องจัดสรรวัตถุแบบไดนามิก:

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

12
vec.push_back(std::unique_ptr<int>(new int(1)));เนื่องจากสามารถมีได้เพียงหนึ่งคนหนึ่งก็ควรจะสามารถที่จะผ่านชั่วคราวโดยตรงกับเวกเตอร์: unique_ptrยังสามารถใช้ deleter แบบกำหนดเอง (ซึ่งไม่ทำอะไรเลย) แต่ก็ต้องคำนึงว่าที่อยู่ของตัวแปรโลคัลกลายเป็นโมฆะในตอนท้ายของขอบเขต
UncleBens

18
emplace_backอีกตัวเลือกหนึ่งคือการใช้งาน เช่นvec.emplace_back(new int(1));
deft_code

75
@deft_code: ไม่นั่นไม่ปลอดภัย การemplace_backดำเนินการสามารถโยนและถ้าเป็นเช่นนั้นการจัดสรรแบบไดนามิกintจะรั่วไหลออกมา กฎง่ายๆคือการจัดสรรแบบไดนามิกทั้งหมดควรเป็นเจ้าของโดยตัวชี้สมาร์ทที่มีชื่อเพื่อหลีกเลี่ยงการรั่วไหล
James McNellis

8
make_shared () ส่งคืน shared_ptr ไม่ใช่ unique_ptr น่าเสียดายที่ไม่มี make_unique () ใน C ++ 11; การละเว้นโชคร้ายที่หวังว่าจะได้รับการแก้ไขใน C ++ 14
cdmh

29
@FKaria make_unique () หมายความว่าnewไม่จำเป็นต้องเรียกใช้โดยตรงซึ่งจะเปลี่ยนความคิดของโปรแกรมเมอร์และหลีกเลี่ยงการรั่วไหลของหน่วยความจำ คำแนะนำเช่น "หลีกเลี่ยงการใหม่และการลบ" สามารถปรากฏในหนังสือ Meyers / Alexandrescu / Sutter ฉบับต่อไป :)
cdmh

24

std :: unique_ptrไม่มีตัวสร้างสำเนา คุณสร้างอินสแตนซ์แล้วขอstd :: vectorเพื่อคัดลอกอินสแตนซ์นั้นในระหว่างการเริ่มต้น

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

คลาสตรงตามข้อกำหนดของ MoveConstructible และ MoveAssignable แต่ไม่ใช่ข้อกำหนดของ CopyConstructible หรือ CopyAssignable

การทำงานต่อไปนี้ใช้กับการโทรemplaceใหม่

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

ดูที่การใช้ unique_ptr พร้อมคอนเทนเนอร์ไลบรารีมาตรฐานสำหรับการอ่านเพิ่มเติม


5
ดูความคิดเห็นนี้ - emplace_x()ฟังก์ชั่นการใช้งานไม่ปลอดภัยเมื่อใช้ตัวชี้สมาร์ท
Qix - MONICA ถูกยกเลิก

ดังนั้นวิธีที่ดีที่สุดในการจัดเก็บ unique_ptr ลงในเวกเตอร์คืออะไร มันช้ามากเมื่อเทียบกับตัวชี้แบบดิบขณะที่ฉันทดสอบ
user2189731
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.