【问题标题】:Is there any way to insert a unique_ptr into a map in C++0x/gcc 4.4.7)?有没有办法在 C++0x/gcc 4.4.7 中将 unique_ptr 插入到地图中?
【发布时间】:2015-12-31 16:24:30
【问题描述】:

我不知道该怎么做;快把我逼疯了。

#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_backunique_ptrs 变成vectors 就好了;我不明白为什么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

【问题讨论】:

  • 尝试提升。 4.4.7 太旧,无法支持标准。
  • @n.m.:Boost 无法解决这个问题。包含/链接 Boost 不能神奇地为语言添加移动语义。
  • 其实c++0x模式下的gcc 4.4.7已经支持移动语义:gcc.gnu.org/projects/cxx0x.html.
  • @LightnessRacesinOrbit boost::unique_ptr 是在移动语义之前发明的。
  • @n.m.:什么? “unique_ptr 不是 CopyConstructible,也不是 CopyAssignable,但它是 MoveConstructible 和 Move-Assignable。”您还期望它如何工作?您是否将它与它所取代的 std::auto_ptr 混淆了?

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


【解决方案1】:

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;

【讨论】:

  • 祝你好运。他不喜欢这个答案。
  • 编译器不需要生成它们,它们包含在 gcc 4.4 的 stl_map 实现中
  • 好吧,听起来我的问题的答案就是“不”——这很好;我会想出别的办法。感谢您的帮助!
【解决方案2】:

我已经调查了这个问题。 map 的 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: 在构造函数'std::_Rb_tree_node<_val>::_Rb_tree_node(_Args&& ...) [with _Args = const std::pair<... std::unique_ptr> >&,

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

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

【讨论】:

  • 感谢您对此进行调查!老实说,这超出了我的想象,不幸的是,我不能摆弄 STL 标头,原因与我不能简单地升级到更新版本的 GCC 相同,但我真的很感谢你四处挖掘。我想我只能接受我想做的事情是不可能的,然后继续前进。
猜你喜欢
  • 2013-05-31
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
相关资源
最近更新 更多