使用initializer_list初始化指向数组的unique_ptr遇C2664编译错误
哈哈,这个坑我之前也踩过!咱们一步步拆解来弄明白编译器为啥给你抛这个错误。
核心原因:std::array没有接受initializer_list的构造函数
你平时写std::array<int, 3> arr = {1, 2, 3};能成功,不是因为std::array有对应的构造函数,而是因为它是C++里的聚合类型——聚合类型可以直接用花括号做元素初始化,不需要专门的构造函数支持。
而当你尝试用std::make_unique<std::array<int,3>>({1,2,3})这类代码初始化unique_ptr时,std::make_unique会尝试把你传的initializer_list作为参数,去调用std::array的构造函数。但翻遍std::array的构造函数列表,你会发现它只有:
- 默认构造函数
- 拷贝构造函数
- 移动构造函数
完全没有接受std::initializer_list的版本!
错误提示的由来
编译器找不到匹配的构造函数时,会尝试做隐式转换来“凑”出可行的调用——比如它会想:能不能把initializer_list转换成const std::array&,然后调用拷贝构造函数?但initializer_list和std::array是完全不同的类型,根本没有这种隐式转换路径,于是就抛出了C2664错误,告诉你没法把initializer_list转成const std::array&。
正确的初始化方式
给你两种靠谱的解决办法:
方法一:先构造好std::array,再转移给unique_ptr
std::array<int, 3> arr = {1, 2, 3}; auto ptr = std::make_unique<std::array<int, 3>>(std::move(arr));用
std::move避免不必要的拷贝,效率更高。方法二:直接new的时候用聚合初始化
auto ptr = std::unique_ptr<std::array<int, 3>>(new std::array<int, 3>{1, 2, 3});这里直接在new的时候用花括号做聚合初始化构造std::array,再把指针传给unique_ptr的构造函数,完美绕开构造函数匹配的问题。
另外提一句:你查到的“可行”资料,大概率是把指向C风格数组的unique_ptr和指向std::array的unique_ptr搞混了——这俩是完全不同的场景,别搞混哦!
内容的提问来源于stack exchange,提问作者FirstProphet

