在下面的示例中,从第一个映射中获取值并插入第二个映射后,共享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)
答案 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
不会修改传递的值。