使用初始化列表初始化std::unique_ptr容器问题续(std::map场景)
std::map初始化std::unique_ptr<T>失败的原因 Hey there! Let's dig into why your initial std::map setup with std::unique_ptr failed, while the std::vector version worked perfectly. First, let's recap the code snippets you provided, then break down the root cause.
可行的std::vector初始化代码
This one works smoothly thanks to how vector handles initialization lists and unique_ptr's move semantics:
#include <vector> #include <memory> int main() { std::vector<std::unique_ptr<int>> vec = { std::make_unique<int>(1), std::make_unique<int>(2), std::make_unique<int>(3) }; return 0; }
报错的std::map初始化代码
This version throws a compile error tied to unique_ptr's deleted copy constructor:
#include <map> #include <memory> int main() { // 编译报错:尝试调用已被删除的unique_ptr拷贝构造函数 std::map<int, std::unique_ptr<int>> map = { {1, std::make_unique<int>(1)}, {2, std::make_unique<int>(2)}, {3, std::make_unique<int>(3)} }; return 0; }
A typical error message looks like:
use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
调试成功的std::map实现
Here are the working approaches you landed on:
#include <map> #include <memory> int main() { // 方式1:显式用std::move转移所有权 std::map<int, std::unique_ptr<int>> map1 = { {1, std::move(std::make_unique<int>(1))}, {2, std::move(std::make_unique<int>(2))}, {3, std::move(std::make_unique<int>(3))} }; // 方式2:用emplace直接在map内存中构造元素 std::map<int, std::unique_ptr<int>> map2; map2.emplace(1, std::make_unique<int>(1)); map2.emplace(2, std::make_unique<int>(2)); map2.emplace(3, std::make_unique<int>(3)); // 方式3:显式构造pair对象 std::map<int, std::unique_ptr<int>> map3 = { std::pair<int, std::unique_ptr<int>>(1, std::make_unique<int>(1)), std::pair<int, std::unique_ptr<int>>(2, std::make_unique<int>(2)) }; return 0; }
核心原因:vector与map初始化逻辑的差异
First, remember that std::unique_ptr is an exclusive-ownership smart pointer—its copy constructor and copy assignment operator are explicitly deleted. It only supports move semantics to transfer ownership of the underlying pointer.
为什么vector代码能正常运行
When you initialize a vector with {std::make_unique(...), ...}, the compiler directly constructs unique_ptr objects in the vector's internal memory. The make_unique calls return rvalues (temporary objects), and the vector's initializer-list constructor can move these rvalues into place using unique_ptr's valid move constructor. No copy operations are attempted here.
为什么原始map代码失效
std::map stores elements as std::pair<const Key, T> (in your case, pair<const int, unique_ptr<int>>). When you write { {1, make_unique(1)}, ... }, the compiler first tries to construct temporary pair objects from each nested initializer list.
The problem? When initializing the pair's second member (the unique_ptr), the compiler tries to copy the temporary unique_ptr returned by make_unique into the pair. Since unique_ptr's copy constructor is deleted, this triggers a compile error.
Unlike vector, the initializer-list handling for map doesn't automatically move the rvalue into the pair—it treats initializer list elements as const references, which can't trigger a move operation.
为什么修复后的map代码能工作
std::move方式: Explicitly casts the temporaryunique_ptrto an rvalue reference, forcing thepairconstructor to useunique_ptr's move constructor instead of attempting a copy.emplace方式: Constructs thepairdirectly in themap's memory, skipping temporarypairobjects entirely. This transfers ownership of theunique_ptrdirectly into the map's element without any copy attempts.- 显式构造
pair方式: When you explicitly create apairwith an rvalueunique_ptr, thepair's constructor uses move semantics to take ownership of the pointer, avoiding copies.
内容的提问来源于stack exchange,提问作者Sergio Losilla

