Why does this code output garbage on GCC, like there is 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.
Compiler Explorer snippet
I 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 initialization code isn't produced if any of the 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 the lambda expression would have other captures, they would not be initialized either, and capture-by-reference turns into capture-by-value, having a unique address, but uninitialized.
The default constructor don’t have any effect on this behaviour.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With