无法创建MoveConstructibles的地图

时间:2010-02-18 06:58:45

标签: c++11 stdmap unique-ptr

我有一个包含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<>内部发生的事情。

线索?

- 编辑

查看错误消息,实际上恰好是TDM-GCC 4.4.1 std::map<>实现的问题。它似乎没有像std::vector<>::push_back(value_type&&)那样的移动语义感知插入方法。

现在该怎么办?

2 个答案:

答案 0 :(得分:2)

我遇到了同样的问题。通过修补bits / stl_map.h和bits / stl_tree.h,我可以毫不费力地添加所需的功能。为了使您的特定示例正常工作,您基本上只需要向地图类添加insert(value_type&amp;&amp;)方法。它与insert(const value_type&amp;)基本相同,但在适当的地方使用std :: move()。您还必须添加正确的支持方法,但您可以使用编译错误来告诉您需要什么。

此问题已报告给海湾合作委员会小组(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436),有人正在研究这个问题,所以希望我们很快就会看到支持在关联和无序容器中移动构造。

答案 1 :(得分:1)

您使用的是什么编译器?它与VS10 beta 2编译得很好。


编辑:有问题的编译器是GCC

这似乎是STL实施中的一个错误,因为GCC是开源的,您可以提交修补此问题的补丁。
幸运的是,修复程序是在STL代码而不是编译器代码中,所以它不应该太难。

与此同时,您可以在本地pair / map标头文件中输入您的修补程序。