Output is different for R-value and L-value. Why?
-
29-06-2021 - |
Question
Can someone explain to me why output for R-value is different from L-value?
#include <iostream>
#include <vector>
using namespace std;
template<typename Ct>
struct ct_wrapper {
Ct&& ct; // R or L ref
explicit ct_wrapper(Ct&& ct)
: ct(std::forward<Ct>(ct)) { std::cout << this->ct[1];};
};
int main() {
// L-val
vector<int> v{1,2,3};
ct_wrapper<vector<int>&> lv(v);
cout << endl << lv.ct[0] << lv.ct[1] << lv.ct[2] << endl;
// R-val
ct_wrapper<vector<int>&&> rv(vector<int>{1,2,3});
cout << endl << rv.ct[0] << rv.ct[1] << rv.ct[2] << endl;
}
Output (same for gcc48 and clang32):
2
123
2
003
Answer
It was buried somewhat in my chat with Johannes Schaub, so I've put it here.
When temporary vector initializes r-value-ref member-variable rv.ct
, temporary lifetime is not extended because there's a special exception: [class.temporary]p5: "A temporary bound to a reference member in a constructor's ctor-initializer (12.6.2) persists until the constructor exits."
Solution
Because your member is just a reference. In the second case the object it references is already dead after the definition of the local rv
variable has finished. So the later access in the cout
is undefined behavior.
OTHER TIPS
Your program has undefined behaviour because you are accessing a dangling reference. The temporary vector is destroyed at the end of the full-expression in which it appears, and yet you retain a reference to it.
In the r-value case you bind a temporary to the reference. It will already be gone when you get to the last output statement.