有没有办法在C ++ 0x / gcc 4.4.7中将unique_ptr插入到地图中?

时间:2015-12-31 16:24:31

标签: c++ c++11 gcc gcc4.4

我无法弄明白该怎么做;它让我疯了。

#include <iostream>
#include <memory>
#include <map>

int main()
{
    std::map<std::string, std::unique_ptr<std::string>> map;
    std::unique_ptr<std::string> bar(new std::string("bar"));
    map["foo"] = std::move(bar);

    std::cout << "foo: " << *(map["foo"]) << std::endl;
}

这在gcc v4.9.2上编译得很好:

$ g++ -std=c++0x test.cc -o test

不幸的是,我可以使用的只是gcc v4.4.7,它会产生一个可怕的错误信息,我会把它粘在底部。

我可以push_back unique_ptr进入vector就好了;我不明白为什么map存在问题。

我也尝试过使用insert

int main()
{
    std::map<std::string, std::unique_ptr<std::string>> map;
    std::unique_ptr<std::string> bar(new std::string("bar"));
    auto pair = std::make_pair("foo", std::move(bar));
    map.insert(std::move(pair));

    std::cout << "foo: " << *(map["foo"]) << std::endl;
}

我可以让pair很好,但当我尝试将move转换为insert时,我会收到错误消息。它似乎是出于某种原因试图调用复制构造函数,但我不明白为什么,因为我move它。

emplace具有相同的结果:

int main()
{
    std::map<std::string, std::unique_ptr<std::string>> map;
    std::unique_ptr<std::string> bar(new std::string("bar"));
    auto pair = std::make_pair("foo", std::move(bar));
    map.emplace(std::move(pair));

    std::cout << "foo: " << *(map["foo"]) << std::endl;
}

这些都在g ++ v4.9.2中编译得很好,但在v4.4.7中没有编译。

任何人都有其他方法可以做到这一点(在v4.4.7中)?

完整错误消息输出(来自第一个示例):

In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_algobase.h:66,
                 from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/char_traits.h:41, 
                 from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ios:41,                
                 from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:40,            
                 from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/iostream:40,           
                 from test.cc:1:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/unique_ptr.h: In copy constructor 'std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::pair(const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&)':
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h:68:   instantiated from 'std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ext/new_allocator.h:111:   instantiated from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, _Args&& ...) [with _Args = const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, _Tp = std::_Rb_tree_node<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/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 std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/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 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_tree.h:1215:   instantiated from 'std::_Rb_tree_iterator<_Val> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique_(std::_Rb_tree_const_iterator<_Val>, const _Val&) [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_map.h:540:   instantiated from '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 std::map<_Key, _Tp, _Compare, _Alloc>::insert(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, const std::pair<const _Key, _Tp>&) [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp = std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_map.h:450:   instantiated from '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp = std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >]'
test.cc:9:   instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/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 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp_Deleter = std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h:68: error: used here
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/map:60,
                 from test.cc:3:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_tree.h: In constructor 'std::_Rb_tree_node<_Val>::_Rb_tree_node(_Args&& ...) [with _Args = const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&, _Val = std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]':
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_tree.h:136: note: synthesized method 'std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::pair(const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&)' first required here

2 个答案:

答案 0 :(得分:3)

GCC 4.4.7并未提供对C ++ 11功能的完全支持,因此期望所有C ++ 11功能正常工作是不现实的。在这种特殊情况下,编译器不会为您生成移动分配和移动复制方法。因此,当std::map尝试分配或复制时,它会使用常规默认值,而unique_ptr会删除这些默认值。

如果您只需要智能指针,则可以改为使用shared_ptr

std::map<std::string, std::shared_ptr<std::string>> map;
std::shared_ptr<std::string> bar = std::make_shared<std::string>("bar");
map["foo"] = bar;

答案 1 :(得分:1)

我已经调查了这个问题。映射的STL实现正确定义了一个移动构造函数:

#ifdef __GXX_EXPERIMENTAL_CXX0X__
      template<typename... _Args>
        _Rb_tree_node(_Args&&... __args)
    : _Rb_tree_node_base(),
      _M_value_field(std::forward<_Args>(__args)...) { }
#endif
    };

此外,如错误输出中所述,这被调用。 std::pair也定义了移动构造函数,但是没有调用它。

我相信,std::forward并推断出Args的类型是错误的:

  

usr / lib中/ GCC / x86_64的-红帽-LINUX / 4.4.7 /../../../../包括/ C ++ / 4.4.7 /比特/ stl_tree.h:   在构造函数'std :: _ Rb_tree_node&lt; _Val&gt; :: _ Rb_tree_node(_Args&amp;&amp; ...)中   [与_Args = const std :: pair&lt; ...,std :: unique_ptr&lt; ...&gt; &GT;&安培;,

如您所见,_Args的类型是一个const引用,由forward转发,并调用常规对构造函数。

我假设,有人可能会使用stl_tree.h来修复它 - 例如,通过删除std :: forward并将arg转换为rvalue引用。当然,这不正确,但可能适用于特定情况。