According to the standard (draft n3337), §5.1.2/3:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion
class type — called the closure type — whose properties are described below. This class type is not
an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace
scope that contains the corresponding lambda-expression.
In a nutshell, a lambda expression ultimately instantiates an anonymous type (known only to the compiler), containing member variables that store the values indicated in the capture list. So imagine you saw a class that looked like this:
class __IgnoreMe__
{
std::vector<int>& _v;
public:
__IgnoreMe__(std::vector<int>& v)
: _v(v)
{
}
void operator()()
{
}
};
(Note: this isn't exactly how the class created by the compiler looks. The standard lays out specific requirements for generated classes, which I've left out for brevity's sake.)
Now imagine you instantiate that class like this:
auto v = std::vector<int>(1000000);
auto my_lambda = __IgnoreMe__(v);
Can the instantiation of my_lambda
throw an exception? If so, then the construction of the closure object can throw an exception. (It can't, in this case.)
As for providing nothrow guarantees, the standard doesn't require compilers to account for this, but it doesn't prevent them from doing it either. The end of §5.1.2/3 states:
An implementation may define the closure
type differently from what is described below provided this does not alter the observable behavior of the
program other than by changing:
— the size and/or alignment of the closure type,
— whether the closure type is trivially copyable (Clause 9),
— whether the closure type is a standard-layout class (Clause 9), or
— whether the closure type is a POD class (Clause 9).