创建std::reference_wrapper的引用超出作用域后,其行为及代码疑问
问题
当用于创建std::reference_wrapper的引用超出作用域时,会发生什么?若底层对象仍然存在,该wrapper是否仍能访问该对象?还是会变为悬空引用,使用它会导致未定义行为(UB)?
实验代码
#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; }
输出结果
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
修改后的测试代码
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; }
结论与解释
std::reference_wrapper本质是对普通引用的封装,行为和普通引用完全一致:
- 当用于创建wrapper的中间引用超出作用域时,只要底层对象仍存活,wrapper不会变成悬空引用。因为wrapper绑定的是底层对象本身,而非那个中间引用。比如修改后的代码里,
mref1到mref4都是全局对象m的引用,即使这些中间引用在fill函数结束后销毁,wrapper绑定的依然是m,所以可以正常访问。 - 只有当wrapper绑定的底层对象被销毁时,它才会变为悬空引用,此时访问会触发未定义行为。
你的实验代码运行正常是预期行为:
- 初始
r绑定的a在main全程存活; - 后续
rwrap = std::ref(m)将r重新绑定到全局对象m,m的生命周期覆盖整个程序,所以所有访问都是合法的,并非侥幸。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

