What happens to a std::reference_wrapper if the reference used to create it goes out of scope? Can it still still provide access to the underlying object (which would still exist), or would it be dangling and attempts to use it would result in UB?
I was experimenting with this code, and it compiled and run. Was I just lucky, or is this the expected behavior?
#include <iostream>
using namespace std;
struct mytype {
int stuff;
};
mytype m;
bool myfunc(mytype& my) { return my.stuff > 0; }
void fill(std::reference_wrapper<mytype>& rwrap) {
std::cout << "entering fill" << std::endl;
std::cout << "myfunc(rwrap) : " << myfunc(rwrap) << std::endl;
rwrap = std::ref(m);
std::cout << "myfunc(rwrap): " << myfunc(rwrap) << std::endl;
std::cout << "fill done" << std::endl;
}
int main() {
mytype a;
a.stuff = 7;
std::reference_wrapper<mytype> r = a;
std::cout << "a.stuff: " << a.stuff << std::endl;
std::cout << "r.stuff(pre): " << r.get().stuff << std::endl;
std::cout << "myfunc(r):" << myfunc(r) << std::endl;
fill(r);
std::cout << "r.stuff(post): " << r.get().stuff << std::endl;
std::cout << "myfunc 4: " << myfunc(r) << std::endl;
std::cout << "a.stuff: " << a.stuff << std::endl;
}
output:
a.stuff: 7
r.stuff(pre): 7
myfunc(r):1
entering fill
myfunc(rwrap) : 1
myfunc(rwrap): 0
fill done
r.stuff(post): 0
myfunc 4: 0
a.stuff: 7
Code at compiler explorer: https://godbolt.org/z/4eTnbvqjT
EDIT: This worked too. Just made it to demo to myself how it all "collapses".
void fill(std::reference_wrapper<mytype>& rwrap) {
mytype& mref1 = m;
mytype& mref2 = mref1;
mytype& mref3 = mref2;
mytype& mref4 = mref3;
std::cout << "entering fill" << std::endl;
std::cout << "myfunc(rwrap) : " << myfunc(rwrap) << std::endl;
rwrap = std::ref(mref4);
std::cout << "myfunc(rwrap): " << myfunc(rwrap) << std::endl;
std::cout << "fill done" << std::endl;
}
rwrap = std::ref(m);
This rebinds rwrap
, a.k.a. r
, as a reference to m
.
m
goes out of scope and gets destroyed when fill
returns. Subsequence usage of r
results in undefined behavior.
if the reference used to create it goes out of scope?
It is not std::ref(m)
that goes out of scope and gets destroyed here. That's fine and dandy. Once the assignment rebinds wrap, the reference it gets rebound from is something that nobody cares about any more.
It's not that the reference that goes out of scope that results in undefined behavior, here, but the underlying objects going poof when fill
returns.
You then changed the code example so that m
is now a global object, instead of declared local to the function, so it now continues to exist, and this is now well-defined. The reasoning is identical, the fact that the reference wrapper was initialized from a different reference wrapper is, still, immaterial.