原地创建含unique_ptr的对象时MSVC编译失败问题咨询
MSVC 2019早期版本emplace_back含unique_ptr的unordered_map编译错误分析
没错,这确实是MSVC 2019 16.2.1版本的编译器Bug,属于标准库实现对C++移动语义的处理失误。
问题到底出在哪?
当你试图用emplace_back向vector里构造std::unordered_map<int, std::unique_ptr<int>>时,MSVC的标准库底层错误地尝试调用了std::pair的拷贝构造函数——而std::pair里包含不可拷贝的std::unique_ptr,直接触发了C2280的“引用已删除函数”错误。
哪怕你用了原地构造的写法(比如emplace_back()或emplace_back(hash_int_uptr{})),早期MSVC的vector::emplace_back在处理嵌套容器类型时,没有正确走移动构造的逻辑,反而错误回退到了拷贝构造的路径上。
可行的解决办法
这里有几个靠谱的修复方案,按优先级推荐:
- 优先升级MSVC版本:这个Bug在MSVC 2019 16.3及之后的版本里已经被官方修复了,升级编译器是一劳永逸的解决方式。
- 显式强制移动语义:用
std::move明确告诉编译器走移动路径,修改代码如下:#include <memory> #include <vector> #include <unordered_map> int main() { using hash_int_uptr = std::unordered_map<int, std::unique_ptr<int>>; std::vector<hash_int_uptr> v; v.push_back(std::move(hash_int_uptr{})); // 显式触发移动 } - 临时对象手动转移:先创建一个局部临时对象,再通过
std::move传入emplace_back,写法如下:hash_int_uptr temp; v.emplace_back(std::move(temp));
关于你的几个对比场景
你提到的几个测试结果正好能佐证这个Bug的特殊性:
- 换成
std::shared_ptr能正常编译,是因为shared_ptr本身支持拷贝,就算编译器错误调用拷贝构造也不会触发删除函数的报错。 - 直接
emplace_back单个unique_ptr没问题,是因为vector处理单个unique_ptr的emplace逻辑没有触发这个针对容器内部pair的拷贝Bug。
内容的提问来源于stack exchange,提问作者vsoftco
相关产品推荐
相关产品推荐

