使用基于范围的for循环访问shared_ptr包装的vector出现异常结果
为什么基于范围的for循环输出与vector存储内容不符?
我编写了如下C++代码,运行后发现基于范围的for循环输出和vector中存储的内容不一致:
#include <iostream> #include <memory> #include <vector> using namespace std; shared_ptr<vector<double>> get_ptr() { vector<double> v{1, 2, 3, 4, 5}; return make_shared<vector<double>>(v); } int main() { auto vec = get_ptr(); for (int i = 0; i<get_ptr()->size(); ++i) { std::cout << (*get_ptr())[i] << std::endl; } for (auto v: (*get_ptr())) { std::cout << v << std::endl; } }
Ubuntu系统上的输出:
1 2 3 4 5 4.67913e-310 4.67913e-310 3 4 5
问题原因
- 每次调用
get_ptr()都会生成全新的vector:get_ptr()函数每次被调用时,都会创建一个新的vector<double>实例,并返回指向该实例的shared_ptr。 - 范围for循环中临时对象的生命周期未被延长:在基于范围的for循环
for (auto v: (*get_ptr()))中,(*get_ptr())会生成一个临时的vector对象。根据C++标准,绑定到范围for循环引用的临时对象,其生命周期不会被延长到循环结束——临时对象在循环初始化阶段结束后就会被销毁,后续循环中使用的迭代器会变成悬垂迭代器,访问这些迭代器指向的内存会导致未定义行为,输出垃圾值。
第一个普通for循环看似正常只是巧合:每次循环判断条件和访问元素时调用get_ptr(),都会生成一个新的、内容正确的vector,所以每次访问的都是新vector的有效元素,但这种写法非常低效且存在隐患。
解决方案
直接复用已经获取到的shared_ptr对象vec,避免重复调用get_ptr()生成临时对象:
修改后的main函数:
int main() { auto vec = get_ptr(); // 复用vec,避免重复创建vector for (int i = 0; i < vec->size(); ++i) { std::cout << (*vec)[i] << std::endl; } // 用vec指向的vector遍历,不再生成临时对象 for (auto v: (*vec)) { std::cout << v << std::endl; } }
修改后两次循环都会访问同一个vector实例,输出结果会完全符合预期:
1 2 3 4 5 1 2 3 4 5
内容的提问来源于stack exchange,提问作者tesla1060
相关产品推荐
相关产品推荐

