使用std::map::try_emplace返回值获取unique_ptr为何出现悬垂指针?
问题分析与解决
你遇到的问题是结构化绑定的用法细节导致的——用auto&&绑定try_emplace返回的临时pair时,得到的迭代器是右值引用,在某些编译器实现下会引发未定义行为,导致后续访问对象失效。而用find二次查找能避开这个问题,是因为find返回的是独立的左值迭代器,不存在临时对象生命周期的隐患。
为什么第一种代码失效?
std::map::try_emplace返回的是一个临时的std::pair<iterator, bool>。当你写auto&& [where, inserted]时,where是这个临时pair里迭代器的右值引用。虽然C++标准允许用右值迭代器访问元素,但部分编译器对这种场景的处理存在异常,会让where->second.get()拿到的指针出现悬空或无法正确访问对象。
最简单的修正方法
把结构化绑定的auto&&改成auto,直接拷贝迭代器而非引用:
std::map<std::string, std::unique_ptr<Feature>> Feature::s_registry{}; Feature* Feature::CreateFeature(Map* map, const XMLElement& elem) { auto new_feature = std::make_unique<Feature>(map, elem); std::string new_feature_name = new_feature->name; // 用auto直接拷贝迭代器,避免右值引用问题 if(auto [where, inserted] = s_registry.try_emplace(new_feature_name, std::move(new_feature)); inserted) { return where->second.get(); } else { if(where != std::end(s_registry)) { return where->second.get(); } } return nullptr; }
原理说明
用auto [where, inserted]时,where是迭代器的独立拷贝,属于左值对象,生命周期覆盖整个if语句块。而std::map的插入操作不会让任何现有迭代器失效,所以where指向的元素始终有效,返回的指针自然稳定可靠,完全不需要额外调用find。
另外你提前拷贝new_feature_name的做法是正确的,避免了new_feature被move后无法读取name的问题。
内容的提问来源于stack exchange,提问作者Casey
相关产品推荐
相关产品推荐

