插入无序映射将共享ptr变为null

Insert into a unordered map changes the share ptr to null

本文关键字:ptr 变为 null 共享 无序 映射 插入      更新时间:2023-10-16

在下面的示例中,从第一个map中取出值并插入到第二个map后,共享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;
        }
    }
}

c++ -std=c++11 testsharedptr.cpp - 0 testsharedptr

gcc version 4.8.1

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

根本原因是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_ptrmap1被设置为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 );