【问题标题】:Insert into a unordered map changes the share ptr to null插入无序映射将共享 ptr 更改为 null
【发布时间】:2015-07-17 02:25:56
【问题描述】:

在下面的示例中,在从第一个映射中获取值并插入到第二个映射中之后,共享 ptr 变为空。甚至没有调用析构函数。我不明白到底出了什么问题

#include <iostream>
#include <memory>
#include <unordered_map>

class Test
{
    public:
        Test(){}
        ~Test(){}

        int test;
};

typedef std::shared_ptr<Test> Test_ptr;
typedef std::unordered_map<std::string, Test_ptr> TestMap;

int main()
{
    TestMap map1, map2;
    std::string key("abc");
    Test_ptr ptr(new Test);
    map1.insert(TestMap::value_type(key, ptr));

    TestMap::iterator iter = map1.find(key);
    if (iter != map1.end())
    {
        map2.insert(*iter);
        if (iter->second == nullptr)
        {
            std::cout << "after insert the shared ptr becomes null"  << std::endl;
        }
    }
}

g++ -std=c++11 testsharedptr.cpp -o testsharedptr

gcc 版本 4.8.1 (GCC)

【问题讨论】:

  • 当我编译并运行这个程序时,它没有打印任何东西。
  • 3 for 3 不可重现。你能提供你用来构建的编译器和命令行吗?也许您的特定构建环境中有一些东西?
  • g++ -std=c++11 testsharedptr.cpp -o testsharedptr
  • gcc 版本 4.8.1 (GCC)

标签: c++ shared-ptr


【解决方案1】:

我无法使用 GCC 4.9.2 重现该问题。但是,我能够使用 GCC 4.8.1 重现它。

根本原因是以下std::unordered_map::insert()重载的libstdc++实现中的bug

template< class P >
std::pair<iterator,bool> insert( P&& value );

GCC 4.8.1 的实现是

template<typename _Pair, typename = typename std::enable_if<std::is_constructible<value_type, _Pair&&>::value>::type>
std::pair<iterator, bool>
insert(_Pair&& __x)
{ return _M_h.insert(std::move(__x)); }

而 GCC 4.9.2 的实现是

template<typename _Pair, typename = typename std::enable_if<std::is_constructible<value_type, _Pair&&>::value>::type>
std::pair<iterator, bool>
insert(_Pair&& __x)
{ return _M_h.insert(std::forward<_Pair>(__x)); }

在 GCC 4.8.1 的情况下,您传递的映射条目被移动到 map2 而不是复制。因此,来自map1std::shared_ptr 被设置为nullptr 作为移动的副作用。

如果可能,我建议升级到已修复此错误的 GCC 4.8.2 或更高版本。

如果您无法升级,使用const_iterator 将产生预期的行为:

TestMap::const_iterator iter = map1.find(key);

通过使用const_iterator,您将强制调用此重载:

std::pair<iterator,bool> insert( const value_type& value );

不修改传递的值。

【讨论】:

  • 当你不打算修改容器时使用const_iterator的另一个原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多