Insertion into an unordered map changes the ptr share to null

In the example below, after extracting the value from the first map and inserting into the second map, the total ptr becomes null. Even the destructor is not called. I can't figure out what exactly is wrong.

#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 version 4.8.1 (GCC)

+3


source to share


1 answer


I have not been able to reproduce the problem using GCC 4.9.2. However, I was able to reproduce it using GCC 4.8.1.

The main reason is a bug in the libstdc ++ implementation from the following std::unordered_map::insert()

overload

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

      

GCC implementation 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)); }

      

and the implementation of GCC 4.9.2 is

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)); }

      



In the case of GCC 4.8.1, the portable map entry is moved to map2

instead of being copied. Thus, std::shared_ptr

from map1

gets its value nullptr

as a side effect of the move.

If possible, I would recommend moving to GCC 4.8.2 or newer, which has fixed this bug.

If you are unable to complete the upgrade, using const_iterator

will result in the expected behavior:

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

      

By using const_iterator

, you call this overload:

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

      

which does not change the passed value.

+6


source







All Articles