Tại sao tôi không thể đẩy một unique_ptr vào một vectơ?


217

Có gì sai với chương trình này?

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

Lỗi:

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

Câu trả lời:


328

Bạn cần di chuyển unique_ptr:

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

unique_ptrđảm bảo rằng một unique_ptrcontainer duy nhất có quyền sở hữu con trỏ bị giữ. Điều này có nghĩa là bạn không thể tạo bản sao của một unique_ptr(vì sau đó hai người unique_ptrsẽ có quyền sở hữu), vì vậy bạn chỉ có thể di chuyển nó.

Lưu ý, tuy nhiên, việc sử dụng hiện tại của bạn unique_ptrlà không chính xác. Bạn không thể sử dụng nó để quản lý một con trỏ tới một biến cục bộ. Thời gian tồn tại của một biến cục bộ được quản lý tự động: các biến cục bộ bị hủy khi khối kết thúc (ví dụ: khi hàm trả về, trong trường hợp này). Bạn cần phân bổ động đối tượng:

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

12
Vì chỉ có thể có một, nên người ta cũng có thể truyền tạm thời trực tiếp vào vectơ : vec.push_back(std::unique_ptr<int>(new int(1)));. unique_ptrcũng có thể sử dụng một deleter tùy chỉnh (không có gì), nhưng sau đó người ta phải tính đến việc địa chỉ của biến cục bộ trở nên không hợp lệ ở cuối phạm vi.
ChúBens

18
Một lựa chọn khác là sử dụng emplace_back. ví dụvec.emplace_back(new int(1));
deft_code

75
@deft_code: Không, điều đó không an toàn. Các emplace_backhoạt động có thể ném, và nếu nó, phân bổ động intsẽ bị rò rỉ. Nguyên tắc chung là tất cả các phân bổ động phải được sở hữu bởi một con trỏ thông minh có tên để tránh rò rỉ.
James McNellis

8
make_ Shared () trả về shared_ptr, không phải unique_ptr. Thật không may, không có make_unique () trong C ++ 11; một thiếu sót đáng tiếc hy vọng sẽ được khắc phục trong C ++ 14
cdmh

29
@FKaria make_unique () có nghĩa là newkhông bao giờ cần phải được gọi trực tiếp, điều này làm thay đổi suy nghĩ của lập trình viên và tránh (giảm đáng kể) rò rỉ bộ nhớ. Lời khuyên như "Tránh mới và xóa" sau đó có thể xuất hiện trong phiên bản tiếp theo của cuốn sách Meyers / Alexandrescu / Sutter's :)
cdmh

24

std :: unique_ptr không có hàm tạo sao chép. Bạn tạo một thể hiện và sau đó yêu cầu std :: vector sao chép thể hiện đó trong quá trình khởi tạo.

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

Lớp đáp ứng các yêu cầu của MoveConstructible và MoveAssignable, nhưng không phải là các yêu cầu của CopyConstructible hoặc CopyAssignable.

Sau đây hoạt động với các cuộc gọi emplace mới .

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

Xem sử dụng unique_ptr với các thùng chứa thư viện tiêu chuẩn để đọc thêm.


5
Xem bình luận này - sử dụng các emplace_x()chức năng không an toàn khi sử dụng con trỏ thông minh.
Qix - MONICA ĐƯỢC PHÂN PHỐI

Vì vậy, cách tốt nhất để lưu trữ unique_ptr vào vector là gì? Nó cực kỳ chậm so với con trỏ thô như tôi đã thử nghiệm.
user2189731
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.