Namespaces
Variants

return statement

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
goto - return
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

终止当前函数并将指定值(如果有)返回给调用者。

目录

语法

attr  (可选) return expression  (可选) ; (1)
attr  (可选) return braced-init-list ; (2) (C++11 起)
attr  (可选) co_return expression  (可选) ; (3) (C++20 起)
attr  (可选) co_return braced-init-list ; (4) (C++20 起)
attr - (since C++11) 任意数量的 属性 序列
expression - 可转换为函数返回类型的 表达式
braced-init-list - 花括号初始化列表

说明

1) 计算 表达式 的值,在将结果 隐式转换 为函数返回类型后,终止当前函数并将结果返回给调用方。对于返回类型为(可能带有cv限定符) void 的函数, 表达式 是可选的;在构造函数和析构函数中则不允许使用 表达式
2) 使用 copy-list-initialization 来构造函数的返回值。
3,4) 在协程中,必须使用关键字 co_return 替代 return 作为最终挂起点(详见 协程 说明)。

表达式 花括号初始化列表 (C++11 起) (若存在)被称为 return 语句的 操作数

函数调用结果的复制初始化与 表达式 末尾所有临时对象的销毁之间存在一个 顺序点

(C++11 前)

函数调用结果的复制初始化 先序于 表达式 末尾所有临时对象的销毁,而后者又 先序于 包围 return 语句的块中局部变量的销毁。

(C++11 起)

若函数返回类型为引用类型,且 return 语句 (1,2) 将返回的引用绑定到 临时表达式 的结果,则程序非良构。

(C++26 起)

如果控制流程到达

  • 返回类型为(可能带有 cv 限定符) void 的函数,
  • 构造函数,
  • 析构函数,或
  • 返回类型为(可能带有 cv 限定符) void 的函数的 函数 try

在没有遇到 return 语句的情况下,将执行 return ;

如果控制流程到达 main 函数 的末尾,将执行 return 0 ;

从值返回函数末尾流出(除了 main 函数 和特定的 协程 (C++20 起) ),而没有 return 语句是未定义行为。

在返回(可能带有 cv 限定符) void 的函数中,若表达式类型为(可能带有 cv 限定符的) void ,则可以使用带 expression return 语句。

若函数的返回类型被指定为 占位类型 ,则将从返回值 推导 其类型。若使用 decltype ( auto ) ,类型推导会将可视为 实体 表达式 作为 实体 处理。

(since C++14)

注释

以值返回可能涉及临时对象的构造和复制/移动,除非使用了 复制消除 。具体而言,复制/移动的条件如下:

自动从局部变量和参数移动

表达式 是(可能带括号的) 标识符表达式 ,且命名的自动存储期变量类型满足以下条件时,该表达式具有 移动资格

  • 非volatile对象类型
(since C++11)
  • 或非volatile对象类型的右值引用
(since C++20)

且该变量声明于

  • 最内层外层函数或lambda表达式的
  • 函数体内
  • 或作为参数声明
(since C++11)

表达式 具有移动资格,则进行 重载决议 以选择用于初始化返回值的构造函数 (或对于 co_return ,选择 promise. return_value ( ) 的重载) (since C++20) 时会执行 两次 :

  • 若第一次重载决议失败
(since C++11)
(until C++23)
  • 或决议成功但未选择 移动构造函数 (正式而言,所选构造函数的第一个参数不是 表达式 类型的(可能带cv限定符的)右值引用)
(since C++11)
(until C++20)
  • 随后按常规方式进行重载决议,将 表达式 视为左值(因此可能选择 拷贝构造函数 )。
(since C++11)
(until C++23)

表达式 具有移动资格,则将其视为亡值(因此重载决议可能选择 移动构造函数 )。

(since C++23)

保证的拷贝消除

表达式 是纯右值,则结果对象直接由该表达式初始化。当类型匹配时,该过程不涉及拷贝或移动构造函数(参见 拷贝消除 )。

(since C++17)
功能测试宏 标准 功能
__cpp_implicit_move 202207L (C++23) 简化的 隐式移动

关键词

return co_return

示例

#include <iostream>
#include <string>
#include <utility>
void fa(int i)
{
    if (i == 2)
        return;
    std::cout << "fa("<< i << ")\n";
} // 隐式返回
int fb(int i)
{
    if (i > 4)
        return 4;
    std::cout << "fb(" << i << ")\n";
    return 2;
}
std::pair<std::string, int> fc(const char* p, int x)
{
    return {p, x};
}
void fd()
{
    return fa(10); // fa(10) 是 void 表达式
}
int main()
{
    fa(1); // 打印参数后返回
    fa(2); // 当 i == 2 时不执行任何操作,直接返回
    int i = fb(5); // 返回 4
    i = fb(i);     // 打印参数后返回 2
    std::cout << "i = " << i << '\n'
              << "fc(~).second = " << fc("Hello", 7).second << '\n';
    fd();
}
struct MoveOnly
{
    MoveOnly() = default;
    MoveOnly(MoveOnly&&) = default;
};
MoveOnly move_11(MoveOnly arg)
{
    return arg; // 正确:隐式移动
}
MoveOnly move_11(MoveOnly&& arg)
{
    return arg; // C++20 起正确:隐式移动
}
MoveOnly&& move_23(MoveOnly&& arg)
{
    return arg; // C++23 起正确:隐式移动
}

输出:

fa(1)
fb(4)
i = 2
fc(~).second = 7
fa(10)

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用范围 发布时行为 正确行为
CWG 1541 C++98 若返回类型为 cv 限定 void 则不能省略 expression 允许省略
CWG 1579 C++11 不允许通过转换移动构造函数返回 启用转换移动
构造函数查找
CWG 1885 C++98 未明确自动变量析构的顺序规则 添加顺序规则

参见

C 文档 关于 return 语句