return statement
Terminates the current function and returns the specified value (if any) to its caller.
Syntax
attr(optional) return expression(optional) ;
|
(1) | ||||||||
attr(optional) return braced-init-list ;
|
(2) | (since C++11) | |||||||
attr(optional) co_return expression(optional) ;
|
(3) | (since C++20) | |||||||
attr(optional) co_return braced-init-list ;
|
(4) | (since C++20) | |||||||
attr(C++11) | - | optional sequence of any number of attributes |
expression | - | expression, convertible to the function return type |
braced-init-list | - | brace-enclosed list of initializers and other braced-init-lists |
Explanation
Notes
If control reaches the end of a function with the return type void
(possibly cv-qualified), end of a constructor, end of a destructor, or the end of a function-try-block for a function with the return type (possibly cv-qualified) void
without encountering a return statement, return; is executed.
If control reaches the end of the main function, return 0; is executed.
Flowing off the end of a value-returning function (except main) without a return statement is undefined behavior.
In a function returning void, the return statement with expression can be used, if the expression type is void.
Returning by value may involve construction and copy/move of a temporary object, unless copy elision is used. Specifically, the conditions for copy/move are as follows:
If expression is an lvalue expression that is the (possibly parenthesized) name of an automatic storage duration object declared in the body or as a parameter of the innermost enclosing function or lambda expression, then overload resolution to select the constructor to use for initialization of the returned value or, for co_return, to select the overload of promise.return_value() (since C++20) is performed twice: first as if expression were an rvalue expression (thus it may select the move constructor), and if no suitable conversion is available, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed a second time, with expression considered as an lvalue (so it may select the copy constructor taking a reference to non-const). |
(since C++11) |
The copy-initialization of the result of the function call is sequenced-before the destruction of all temporaries at the end of expression, which, in turn, is sequenced-before the destruction of local variables of the block enclosing the return statement. |
(since C++14) |
If expression is a prvalue, the result object is initialized directly by that expression. This does not involve a copy or move constructor when the types match (see copy elision). |
(since C++17) |
Keywords
Example
#include <iostream> #include <string> #include <utility> void fa(int i) { if (i == 2) return; std::cout << i << '\n'; } // implied return; int fb(int i) { if (i > 4) return 4; std::cout << 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) is a void expression } int main() { fa(2); // returns, does nothing when i==2 fa(1); // prints its argument, then returns int i = fb(5); // returns 4 i = fb(i); // prints its argument, returns 2 std::cout << i << '\n' << fc("Hello", 7).second << '\n'; fd(); }
Output:
1 4 2 7 10
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1579 | C++11 | return by converting move constructor was not allowed | converting move constructor look up enabled |
CWG 1885 | C++14 | sequencing of the destruction of automatic variables was not explicit | sequencing rules added |