仅可移动类返回指针/引用编译失败?是否因RVO被禁用?
问题分析:仅可移动类返回指针解引用/引用时编译失败
示例代码
struct TestCase { TestCase() {} TestCase(const TestCase&) = delete; TestCase(TestCase&&) {} TestCase& operator=(const TestCase&) = delete; TestCase& operator=(TestCase&&) { return *this; } }; TestCase funcReturningOnlyMovableType() { TestCase test_case; TestCase* ptr_test_case = &test_case; TestCase& ref_to_test_case = test_case; return test_case; // WORKS //return *ptr_test_case; // DOESN'T WORK COPY CONSTRUCTOR IS DELETED //return ref_to_test_case; // DOESN'T WORK COPY CONSTRUCTOR IS DELETED } int main() { TestCase test_case = funcReturningOnlyMovableType(); }
用户疑问
定义了一个仅可移动的类,返回指向该类对象的指针解引用结果或对象引用时代码无法编译,请问这是否是因为返回指针或引用指向的对象时RVO(返回值优化)被禁用,进而导致必须调用已被删除的拷贝构造函数?该问题在MSVC、GCC、Clang编译器中均会出现。
解答
是的,你的判断完全正确,具体原因如下:
- 直接返回局部对象
test_case时,编译器可触发返回值优化(RVO):此时编译器会跳过拷贝/移动构造步骤,直接在函数返回值的目标内存位置构造test_case对象,因此不需要调用任何构造函数,代码可以正常编译。 - 返回
*ptr_test_case或ref_to_test_case时,这两个表达式的结果是左值引用(TestCase&),编译器无法触发RVO:RVO的触发条件要求返回的是拥有自动存储期的局部变量本身或未命名临时对象,而指针解引用/引用的结果属于左值,编译器无法确定其是否指向局部变量(理论上可能指向外部对象),因此会禁用RVO。 - 此时编译器尝试将左值作为拷贝构造的参数(左值默认优先匹配拷贝构造),但你的类已删除拷贝构造函数,因此编译报错。
如果要让返回指针解引用或引用的代码通过编译,需要显式将左值转换为右值,触发移动构造:
return std::move(*ptr_test_case); return std::move(ref_to_test_case);
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

