无法创建 MoveConstructibles 的地图
Posted
技术标签:
【中文标题】无法创建 MoveConstructibles 的地图【英文标题】:Can't create map of MoveConstructibles 【发布时间】:2010-02-18 06:58:44 【问题描述】:我有一个包含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&&)
这样的移动语义感知插入方法。
现在该怎么办?
【问题讨论】:
在 ubuntu 上,g++ 4.4.1 明确表示“错误:‘unique_ptr’不是‘std’的成员” 您必须使用--std=c++0x(或--std=gnu++0x,类似的东西)编译您的源代码,才能从<memory>
获得unique_ptr。这可能就是您看到该消息的原因。在这里,unique_ptr 使用得很好。 std::map 就是这么一团糟。
如果它的map
不能处理不可复制的类型,如果你只解决这个单一的问题,它也无济于事。迟早,你会在别处遇到其他问题。
建议?我敢打赌我知道一个:停止依赖标准草案,等待它被标准化并等待完全兼容的编译器出现?天哪,在 C++0x 可以可靠使用之前了解它是受虐狂。我想把它准备好……
【参考方案1】:
我遇到了同样的问题。通过修补 bits/stl_map.h 和 bits/stl_tree.h,我能够毫不费力地添加所需的功能。要使您的特定示例正常工作,您基本上只需向地图类添加一个 insert(value_type&&) 方法。它本质上与 insert(const value_type&) 相同,但在适当的地方使用 std::move()。您还必须添加正确的支持方法,但您可以使用编译错误来告诉您需要什么。
此问题已报告给 GCC 团队 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436),并且有人正在解决此问题,因此希望我们能很快看到对关联容器和无序容器中移动可构造物的支持。
【讨论】:
【参考方案2】:你用的是什么编译器?它可以与 VS10 beta 2 一起编译。
编辑:有问题的编译器是 GCC
这似乎是 STL 实现中的一个错误,因为 GCC 是开源的,您可以提交修复此问题的补丁。 幸运的是,修复是在 STL 代码中,而不是在编译器代码中,所以应该不会太难。
与此同时,您可以在本地 pair
/map
头文件中输入您的修复。
【讨论】:
顺便说一下,它实际上是一个适用于 Windows 的 GCC 4.4.1 端口(TDM-GCC:tdragon.net/recentgcc)。 哈哈。我现在一直在这样做。失败得很惨:]其实我觉得要修补的东西太多,所以我放弃了。我只是想知道.. 如果它没有在 GCC 中实现并且在 VC++ 中实现,那么可能有一个黑暗的原因......不过,我已经向 TDM-GCC 开发人员提交了一个错误报告(这里:@ 987654322@)。谢谢。 暂时,我将只使用boost::ptr_map<>
,即使对象可能已被堆栈分配。当解决方案弹出时,我会更改此设置,如果我在其他地方找到它,我会回答这个问题,以便其他人受益。以上是关于无法创建 MoveConstructibles 的地图的主要内容,如果未能解决你的问题,请参考以下文章