What does "return {}" statement mean in C++11?

Pedia picture Pedia · Sep 14, 2016 · Viewed 25.5k times · Source

What does the statement

return {};

in C++11 indicate, and when to use it instead of (say)

return NULL;

or

return nullptr;

Answer

rgmt picture rgmt · Sep 14, 2016

return {}; indicates "return an object of the function's return type initialized with an empty list-initializer". The exact behaviour depends on the returned object's type.

From cppreference.com (because the OP is tagged C++11, I excluded the rules in C++14 and C++17; refer to the link for further details):

  • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.
  • Otherwise, if T is an aggregate type, aggregate initialization is performed.
  • Otherwise, if T is a specialization of std::initializer_list, the T object is direct-initialized or copy-initialized, depending on context, from the braced-init-list.
  • Otherwise, the constructors of T are considered, in two phases:

    • All constructors that take std::initializer_list as the only argument, or as the first argument if the remaining arguments have default values, are examined, and matched by overload resolution against a single argument of type std::initializer_list
    • If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all).
  • Otherwise (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type that is compatible with the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), except that narrowing conversions are not allowed.

  • Otherwise, if T is a reference type that isn't compatible with the type of the element. (this fails if the reference is a non-const lvalue reference)
  • Otherwise, if the braced-init-list has no elements, T is value-initialized.

Before C++11, for a function returning a std::string, you would have written:

std::string get_string() {
    return std::string();
}

Using the brace syntax in C++11, you don't need to repeat the type:

std::string get_string() {
    return {}; // an empty string is returned
}

return NULL and return nullptr should be used when the function returns a pointer type:

any_type* get_pointer() {
    return nullptr;
}

However, NULL is deprecated since C++11 because it is just an alias to an integer value (0), while nullptr is a real pointer type:

int get_int() {
    return NULL; // will compile, NULL is an integer
}

int get_int() {
    return nullptr; // error: nullptr is not an integer
}