如何正确初始化存储std::reference_wrapper的标准容器(局部对象场景)
问题根源与解决办法
你的代码编译通过但运行时内存损坏,核心原因是局部对象的生命周期不匹配:init()函数里的S1 x和S2 y是栈上的局部变量,当init()执行完毕返回时,这两个对象会被立即销毁。但你的容器v里的std::reference_wrapper<I>还在指向这些已经被释放的内存地址,后续访问自然会触发未定义行为(比如内存损坏、崩溃)。
std::reference_wrapper的本质是对引用的包装,它不负责管理所指向对象的生命周期——你必须确保被包装的对象,在容器的整个使用周期内都处于存活状态。下面是几种正确的初始化方式:
1. 让对象与容器拥有相同(或更长)的生命周期
最直接的方式是把对象放在和容器同作用域(或更外层作用域)的地方,比如main()函数里:
#include <iostream> #include <vector> #include <functional> using namespace std; struct I { virtual void print() = 0; }; struct S1: public I { void print() override { cout << "S1 " << i << endl; } int i{}; }; struct S2: public I { void print() override { cout << "S2 " << f << endl; } float f{}; }; std::vector<reference_wrapper<I>> v; int main() { // 对象在main作用域内,直到程序结束才销毁 S1 x{}; S2 y{}; v.emplace_back(x); v.emplace_back(y); v[1].get().print(); // 安全调用,对象仍存活 return 0; }
2. 用智能指针管理动态分配的对象
如果需要动态创建对象(比如对象数量不确定、需要在函数内创建),可以结合智能指针容器来保证对象的生命周期,再将对象的引用存入reference_wrapper容器:
#include <iostream> #include <vector> #include <functional> #include <memory> using namespace std; struct I { virtual void print() = 0; }; struct S1: public I { void print() override { cout << "S1 " << i << endl; } int i{42}; }; struct S2: public I { void print() override { cout << "S2 " << f << endl; } float f{3.14f}; }; // 用智能指针容器存储对象,确保对象存活 std::vector<std::unique_ptr<I>> object_store; std::vector<reference_wrapper<I>> v; void init() { // 动态创建对象并交由智能指针管理 object_store.emplace_back(make_unique<S1>()); object_store.emplace_back(make_unique<S2>()); // 将对象的引用存入v v.emplace_back(*object_store[0]); v.emplace_back(*object_store[1]); } int main() { init(); v[1].get().print(); // 输出S2 3.14,对象由object_store保证存活 return 0; }
这里object_store容器负责管理动态对象的生命周期,只要object_store不被销毁,v里的引用就始终有效。
3. 使用静态局部对象(谨慎场景)
如果你的场景可以接受全局生命周期的对象,也可以在init()里使用静态局部变量——静态局部变量第一次初始化后,会一直存活到程序结束:
void init() { // 静态局部变量,生命周期覆盖整个程序运行期 static S1 x{}; static S2 y{}; v.emplace_back(x); v.emplace_back(y); }
注意:静态局部变量是单实例的,且初始化的线程安全性需要考虑,不适合所有场景(比如需要多次创建不同实例的情况)。
核心总结
std::reference_wrapper只是引用的"包装器",不承担对象的生命周期管理;- 必须保证
reference_wrapper指向的对象,在容器被访问的整个过程中都处于存活状态; - 绝对避免让
reference_wrapper指向栈上的局部变量(函数返回后变量会被销毁),这是你代码出问题的直接原因。
内容的提问来源于stack exchange,提问作者Student4K
相关产品推荐
相关产品推荐

