有什么方法可以将 unique_ptr 插入到 C++0x/gcc 4.4.7 中的映射中)?

Is there any way to insert a unique_ptr into a map in C++0x/gcc 4.4.7)?

我不知道该怎么做;这让我发疯。

#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 时,我得到了错误。它似乎出于某种原因试图调用复制构造函数,但我不明白为什么,因为我正在 moveing 它。

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

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;

我已经调查了这个问题。地图的 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-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<..., std::unique_ptr<...> >&,

如你所见,_Args的类型是const引用,通过forward转发,调用正则对构造函数

我假设,可能 fiddle 和 stl_tree.h 来修复它 - 例如,通过删除 std::forward 并将 arg 强制转换为右值引用。这当然是不正确的,但可能适用于特定情况。