Не удается создать карту MoveConstructibles

У меня есть класс, содержащий std::unique_ptr<>, и я хочу поместить экземпляры этого класса внутрь std::map<>. Я думал, что одной из причин, побудивших ввести семантику перемещения в C++, была возможность помещать такие вещи, как unique_ptrs, в стандартные контейнеры (и это действительно работает в случае векторов). Но мне кажется, что std::map<> эта идея не нравится. Почему это так?

#include <map>
#include <memory>

int main()
{
    std::map<int,std::unique_ptr<int>> map;

    // error on the line that follows (use of disabled lvalue copy constructor)
    map.insert(std::make_pair(1,std::unique_ptr<int>(new int(2))));

    return 0;
}

Спасибо.

-- редактировать

Просто чтобы быть более ясным, точные сообщения об ошибках:

mingw32-g++.exe --std=gnu++0x   -ID:\CodeEnv\Libraries\Boost  -c D:\CodeEnv\CodeMess\Untitled1.cpp -o D:\CodeEnv\CodeMess\Untitled1.o
mingw32-g++.exe  -o D:\CodeEnv\CodeMess\Untitled1.exe D:\CodeEnv\CodeMess\Untitled1.o   
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_algobase.h:66,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h:62,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/map:60,
                 from D:\CodeEnv\CodeMess\Untitled1.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/unique_ptr.h: In copy constructor 'std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >::pair(const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&)':
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_pair.h:68:   instantiated from 'std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&, _Val = std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/ext/new_allocator.h:111:   instantiated from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, _Args&& ...) [with _Args = const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&, _Tp = std::_Rb_tree_node<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h:394:   instantiated from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&, _Key = int, _Val = std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >, _KeyOfValue = std::_Select1st<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h:881:   instantiated from 'std::_Rb_tree_iterator<_Val> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_(const std::_Rb_tree_node_base*, const std::_Rb_tree_node_base*, const _Val&) [with _Key = int, _Val = std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >, _KeyOfValue = std::_Select1st<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h:1177:   instantiated from 'std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = int, _Val = std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >, _KeyOfValue = std::_Select1st<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_map.h:500:   instantiated from 'std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = int, _Tp = std::unique_ptr<int, std::default_delete<int> >, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, std::unique_ptr<int, std::default_delete<int> > > >]'
D:\CodeEnv\CodeMess\Untitled1.cpp:7:   instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/unique_ptr.h:214: 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>]'
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_pair.h:68: error: used here
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/map:60,
                 from D:\CodeEnv\CodeMess\Untitled1.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h: In constructor 'std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&, _Val = std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >]':
c:\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/stl_tree.h:136: note: synthesized method 'std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >::pair(const std::pair<const int, std::unique_ptr<int, std::default_delete<int> > >&)' first required here 

Может показаться, что это проблема с std::pair<>, но он отлично работает, когда используется один:

int main()
{
    std::pair<int,std::unique_ptr<int>> pair;

    pair = std::make_pair(1,std::unique_ptr<int>(new int(2))); // no errors
    return 0;
}

Хотя это, очевидно, не означает, что его нельзя использовать неправильно:

int main()
{
    std::pair<int,std::unique_ptr<int>> pair1,pair2;

    pair1 = std::make_pair(1,std::unique_ptr<int>(new int(2))); // no errors
    pair2 = pair1; // BOOM ! Copy from lvalue
    return 0;
}

что, вероятно, и происходит внутри std::map<>.

Подсказки?

-- редактировать

Судя по сообщениям об ошибках, это действительно проблема с std::map<> реализацией TDM-GCC 4.4.1. Похоже, что в нем нет метода вставки с учетом семантики перемещения, такого как std::vector<>::push_back(value_type&&).

Что делать сейчас?


person Gui Prá    schedule 18.02.2010    source источник
comment
в Ubuntu g++ 4.4.1 четко говорит об ошибке: ‘unique_ptr’ не является членом ‘std’   -  person amit    schedule 20.02.2010
comment
Вы должны скомпилировать свои исходники с --std=c++0x (или --std=gnu++0x, что-то в этом роде), чтобы unique_ptr был доступен из <memory>. Вероятно, поэтому вы видите это сообщение. Здесь unique_ptr используется нормально. Там как раз такая неразбериха с std::map.   -  person Gui Prá    schedule 23.02.2010
comment
Если его map не может обрабатывать некопируемые типы, это не поможет, если вы будете работать только с этой единственной проблемой. Рано или поздно вы получите другие проблемы в другом месте.   -  person Johannes Schaub - litb    schedule 02.03.2010
comment
Предложения? Бьюсь об заклад, я знаю это: перестаньте полагаться на стандартные черновики, подождите, пока они будут стандартизированы и появятся полностью совместимые компиляторы? Боже, знакомство с C++0x до того, как его можно будет надежно использовать, — это мазохизм. Я так хочу, чтобы он был готов...   -  person Gui Prá    schedule 03.03.2010


Ответы (2)


Я столкнулся с той же проблемой. Я смог без особых усилий добавить необходимую функциональность, исправив файлы bits/stl_map.h и bits/stl_tree.h. Чтобы заставить ваш конкретный пример работать, вам просто нужно добавить метод вставки (value_type &&) в класс карты. По сути, это то же самое, что и вставка (const value_type&), но с использованием std::move(), где это необходимо. Вы также должны добавить правильные методы поддержки, но вы можете использовать ошибки компиляции, чтобы сказать вам, что вам нужно.

Об этой проблеме было сообщено команде GCC (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436), и кто-то работает над этим, поэтому мы надеемся, что скоро мы увидим поддержку перемещения конструируемых объектов в ассоциативных и неупорядоченных контейнерах.

person Mr. Tempastic    schedule 08.07.2010

Какой компилятор вы используете? Он отлично компилируется с VS10 beta 2.


Изменить: речь идет о компиляторе GCC.

Похоже, это ошибка в реализации STL, так как GCC является открытым исходным кодом, вы можете отправить патч, устраняющий эту проблему.
К счастью, исправление находится в коде STL, а не в коде компилятора, так что это не должно быть слишком сложно.

Тем временем вы можете внести свое исправление в локальные заголовочные файлы pair/map.

person Motti    schedule 18.02.2010
comment
Кстати, на самом деле это порт GCC 4.4.1 для Windows (TDM-GCC: tdragon.net/recentgcc< /а>). - person Gui Prá; 18.02.2010
comment
На данный момент я просто буду использовать boost::ptr_map<>, хотя объекты могли быть выделены в стеке. Я изменю это, когда появится решение, и, если я узнаю его где-то еще, я отвечу на этот вопрос, чтобы другие люди получили пользу. - person Gui Prá; 18.02.2010