从函数返回std::vector<std::unique_ptr<T>>时遇编译错误的问题
关于返回
std::vector<std::unique_ptr<int>>的编译错误分析 问题场景
使用MSVC 19.33.31630编译器时,尝试从函数返回std::vector<std::unique_ptr<int>>遇到编译错误,错误提示:
Error C2280 'std::unique_ptr<int,std::default_delete
>::unique_ptr(const std::unique_ptr<int,std::default_delete > &)': attempting to reference a deleted function
测试代码1(按值返回)
std::vector<std::unique_ptr<int>> test1() { std::vector<std::unique_ptr<int>> ret = { std::make_unique<int>(1) }; return ret; } int main() { std::vector<std::unique_ptr<int>> x = test1(); std::unique_ptr<int>& ptrY = x.at(0); return 0; }
测试代码2(返回引用)
std::vector<std::unique_ptr<int>>& test2() { std::vector<std::unique_ptr<int>> ret = { std::make_unique<int>(1) }; return ret; } int main() { std::vector<std::unique_ptr<int>>& y = test2(); std::cout << *(y.at(0)) << std::endl; return 0; }
错误原因解析
两个代码触发编译错误的核心原因一致:使用初始化列表初始化std::vector<std::unique_ptr<int>>时,会尝试调用std::unique_ptr的拷贝构造函数,但该函数已被显式删除。
初始化列表{ std::make_unique<int>(1) }中的元素会被视为const std::unique_ptr<int>&类型,vector初始化时需要将这些元素拷贝到容器内,而std::unique_ptr是独占所有权的智能指针,不允许拷贝操作,因此触发C2280错误。
另外,测试代码2还存在额外的严重问题:返回局部变量的引用属于未定义行为。函数内的局部vectorret在函数执行完毕后会被销毁,返回的引用会变成悬空引用,后续访问会导致程序崩溃或不可预料的行为。
修正方案
方案1:避免使用初始化列表,改用push_back/emplace_back
std::vector<std::unique_ptr<int>> test1() { std::vector<std::unique_ptr<int>> ret; ret.emplace_back(std::make_unique<int>(1)); // 直接在容器内构造unique_ptr,无拷贝 return ret; } int main() { std::vector<std::unique_ptr<int>> x = test1(); std::unique_ptr<int>& ptrY = x.at(0); return 0; }
方案2:直接返回临时vector对象,通过std::move转移所有权
std::vector<std::unique_ptr<int>> test1() { return { std::move(std::make_unique<int>(1)) }; // 转为右值触发移动构造,避免拷贝 }
注意事项
- 永远不要返回局部变量的引用或指针,这会导致悬空引用/指针,引发未定义行为。
std::unique_ptr只能通过移动操作转移所有权,任何尝试拷贝的操作都会触发编译错误。
内容的提问来源于stack exchange,提问作者Scienciser
相关产品推荐
相关产品推荐

