插入无序映射会将共享ptr更改为null

时间:2015-07-16 02:43:14

标签: c++ shared-ptr

在下面的示例中,从第一个映射中获取值并插入第二个映射后,共享ptr变为null。即使是析构函数也没有被调用。我无法理解究竟是什么错误

#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)

1 个答案:

答案 0 :(得分:6)

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

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

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而不是复制。因此,来自std::shared_ptr的{​​{1}}设置为map1,作为移动的副作用。

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

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

const_iterator

通过使用TestMap::const_iterator iter = map1.find(key); ,您将强制调用此重载:

const_iterator

不会修改传递的值。