Чому я не можу не повернути унікальний_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_ptrs мали б право власності), тому ви можете лише перемістити його.

Однак зауважте, що ваше поточне використання unique_ptrневірно. Ви не можете використовувати його для управління вказівником на локальну змінну. Життям локальної змінної управляється автоматично: локальні змінні руйнуються після закінчення блоку (наприклад, коли функція повертається, в цьому випадку). Потрібно динамічно розподілити об’єкт:

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

12
Оскільки може бути тільки один, один повинен також бути в змозі передати тимчасове безпосередньо до вектору: vec.push_back(std::unique_ptr<int>(new int(1)));. unique_ptrможна також використовувати спеціальний делетер (який нічого не робить), але тоді потрібно враховувати, що адреса локальної змінної стає недійсною в кінці області.
UncleBens

18
Інший варіант - використовувати emplace_back. наприкладvec.emplace_back(new int(1));
deft_code

75
@deft_code: Ні, це не безпечно. emplace_backОперація може кинути, і якщо це станеться, динамічно розподіляється intбуде витік. Основне правило полягає в тому, що всі динамічні асигнування повинні належати названому розумному вказівнику, щоб уникнути герметичності.
James McNellis

8
make_shared () повертає спільний_ptr, а не унікальний_ptr. На жаль, в C ++ 11 немає make_unique (); нещасний упущення, яке, сподіваємось, буде зафіксовано в C ++ 14
cdmh

29
@FKaria make_unique () означатиме, що newніколи не потрібно звертатися безпосередньо, що змінює мислення програміста і уникає (значно зменшує) витоку пам'яті. Поради, як "Уникати нового та видаляти", можуть з’явитися в наступному виданні книги
Мейєрса

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

Дивіться використання унікального_ptr зі стандартними бібліотечними контейнерами для подальшого читання.


5
Дивіться цей коментар - використання emplace_x()функцій небезпечно при використанні розумних покажчиків.
Qix - МОНІКА ПОМИЛИЛА

То який найкращий спосіб зберігати унікальний_ptr у вектор? Це надзвичайно повільно порівняно із сирим покажчиком, як я тестував.
користувач2189731
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.