I wrote the following modern C++20 pipeline to filter records returned by a database query helper function:
#include <iostream>
#include <vector>
#include <ranges>
std::vector<int> getTemperatures() {
return {18, 25, 32, 14, 29, 36};
}
int main() {
// Pipeline on temporary container returned by value
auto warm_days = getTemperatures() | std::views::filter([](int t) { return t > 20; });
for (int t : warm_days) {
std::cout << t << " "; // Undefined Behavior / Garbage output!
}
}When compiling with GCC 13 or Clang 17 with -std=c++20, the loop prints garbage values or crashes with a segmentation fault. Why does this trigger undefined behavior when standard STL algorithms work fine?
Direct Technical Solution: In C++20, range view adaptors (like
std::views::filter,std::views::transform, andstd::views::take) are strictly non-owning view wrappers. They do not duplicate or take ownership of the underlying container; they only store iterators pointing directly into the underlying sequence.In your code,
getTemperatures()returns a temporarystd::vector<int>by value. At the semicolon ending the initialization expressionauto warm_days = getTemperatures() | ...;, the temporary vector reaches the end of its full-expression lifetime and is immediately destructed. Consequently, the iterators stored insidewarm_daysbecome dangling pointers into deallocated stack/heap memory, causing undefined behavior upon iteration.