为何结构化绑定后返回std::unique_ptr必须使用std::move?
结构化绑定std::unique_ptr时的C2280错误解析
问题场景
以下代码编译时会触发C2280错误,核心原因是编译器尝试复制std::unique_ptr:
#include <memory> std::pair<int, std::unique_ptr<int>> CreatePair() { std::unique_ptr<int> my_int(new int); return { 1, std::move(my_int) }; } std::unique_ptr<int> GetUinquePtr() { auto [ignore, unique_ptr] = CreatePair(); return unique_ptr; // <- 编译错误C2280:尝试引用已删除的函数 } int main() { auto unique_ptr = GetUinquePtr(); }
完整错误信息:
error C2280: 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function
错误原因
std::unique_ptr是独占所有权的智能指针,其拷贝构造函数被显式删除,仅支持移动语义完成所有权转移。
在结构化绑定auto [ignore, unique_ptr] = CreatePair()中,声明的unique_ptr是原std::pair中对应成员的左值绑定(表现为左值)。直接return unique_ptr时,编译器会尝试调用其拷贝构造函数生成返回值,这就触发了对删除函数的引用错误。
可行写法说明
1. 显式使用std::move
添加std::move后,会将左值类型的unique_ptr转换为右值,触发其移动构造函数,符合std::unique_ptr的所有权转移设计:
std::unique_ptr<int> GetUinquePtr() { auto [ignore, unique_ptr] = CreatePair(); return std::move(unique_ptr); // <- 此写法可行 }
2. 使用std::tie
std::tie会将已声明的unique_ptr与std::pair的成员绑定,这里执行的是移动赋值操作(把CreatePair()返回的pair中的unique_ptr所有权转移到提前声明的变量中)。后续return unique_ptr时,编译器会对局部自动变量执行隐式移动(C++11及以后的规则),因此无需显式std::move:
std::unique_ptr<int> GetUinquePtr() { std::unique_ptr<int> unique_ptr; std::tie(std::ignore, unique_ptr) = CreatePair(); return unique_ptr; // <- 此写法可行 }
结论
是的,通过结构化绑定获取std::unique_ptr后,返回时必须显式使用std::move——因为结构化绑定的变量是左值,默认会触发拷贝操作,而std::unique_ptr禁止拷贝。这并非操作失误,而是完全符合C++中std::unique_ptr的所有权规则和结构化绑定的语义。
内容的提问来源于stack exchange,提问作者Olppah
相关产品推荐
相关产品推荐

