Why this code is not valid?
auto foo = [] () {
return {1, 2};
};
However, this is valid since the initializer_list
is used just to initialize a vector
not to return itself:
auto foo = [] () -> std::vector<int> {
return {1, 2};
};
Why I can not return initializer_list
? It could be useful. For example, a lambda that can be used to initialize a vector
or a list
or ... with some default values for something.
Lambda return type deduction uses the auto
rules, which normally would have deduced std::initializer_list
just fine. However, the language designers banned deduction from a braced initializer list in a return statement ([dcl.spec.auto]/7):
If the deduction is for a
return
statement and the initializer is a braced-init-list ([dcl.init.list]), the program is ill-formed.
The reason for this is that std::initializer_list
has reference semantics ([dcl.init.list]/6).
[]() -> std::initializer_list<int> { return {1, 2}; }
is every bit as bad as []() -> const int & { return 1; }
. The lifetime of the backing array of the initializer_list
object ends when the lambda returns, and you are left with a dangling pointer (or two).
Demo:
#include <vector>
struct Noisy {
Noisy() { __builtin_printf("%s\n", __PRETTY_FUNCTION__); }
Noisy(const Noisy&) { __builtin_printf("%s\n", __PRETTY_FUNCTION__); }
~Noisy() { __builtin_printf("%s\n", __PRETTY_FUNCTION__); }
};
int main()
{
auto foo = []() -> std::initializer_list<Noisy> { return {Noisy{}, Noisy{}}; };
std::vector<Noisy> bar{foo()};
}
Output:
Noisy::Noisy()
Noisy::Noisy()
Noisy::~Noisy()
Noisy::~Noisy()
Noisy::Noisy(const Noisy&)
Noisy::Noisy(const Noisy&)
Noisy::~Noisy()
Noisy::~Noisy()
Note how the copy constructors are called after all the Noisy
objects created so far have been destroyed already.