Why does this code output garbage on GCC like there is a UB?
auto data = std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto output = [data](this auto self, size_t i) {
if (i >= 10) {
return;
}
std::print("{}, ", data[i]);
self(i + 1);
};
output(0);
Changing to capture data
by reference or self
as a reference makes it look fine.
Can narrow it down: it's a GCC bug, featured at least in version 15.2, where for an object created by a lambda expression with deduced this by value, the intialization code isn't produced if any of captures by value is a type with not-defaulted copy or move constructors, a simplest test case here returns 1 whenever at least one constructor of the two is user-defined as not-default:
struct A {
A() {};
A(const A&) {}
//A(const A&) = default;
A(A&&) {}
//A(A&&) = default;
int n = 42;
};
int main() {
auto l = [data = A()](this auto) {
return data.n != 42;
};
return l();
}
If lambda expression would have other captures, they will not be initialized either, and capture-by-reference turns into capture-by-value, having unique address but uninitialzied.
Default constructor have no effect on this behaviour.