如何在map转换中保留struct的有效指针?解决指针失效问题
问题:map转换后指针失效的解决办法
我尝试把o1转换成r1,代码如下:
map<int, vector<vector<myStruct>>> o1; map<int, vector<vector<myStruct*>>> r1; for(int i = 0; i < o1.size(); ++i) { auto element = o1[i]; vector<vector<myStruct*>> tmp; for(int j = 0; j < element.size(); ++j) { tmp.push_back({}); for(int k = 0; k < element[j].size(); ++k) { tmp[j].push_back(&element[j][k]); } } r1[i] = tmp; }
但循环结束后,r1里指向element的指针都失效了,请问怎么修改代码才能让这些指针保持有效?
问题分析与解决方案
嘿,问题根源其实很简单——你这里的auto element = o1[i];是做了值拷贝!也就是说element是o1[i]的一个临时副本,循环结束后这个副本就被销毁了,你存在r1里的指针自然就变成了野指针,指向已经被释放的内存。
要解决这个问题,只需要把值拷贝改成引用,让element直接指向o1里的原始数据,而不是复制一份临时对象。具体修改有两种方式:
方式一:使用引用获取map中的元素
把auto element = o1[i];改成auto& element = o1[i];(注意这里的&符号),这样element就是o1对应键值下的原始vector<vector<myStruct>>的引用,你取的指针都是指向原始容器里的有效对象,循环结束后o1还在的话,这些指针就一直有效。
修改后的完整代码:
map<int, vector<vector<myStruct>>> o1; map<int, vector<vector<myStruct*>>> r1; for(int i = 0; i < o1.size(); ++i) { auto& element = o1[i]; // 这里加了&,变成引用 vector<vector<myStruct*>> tmp; for(int j = 0; j < element.size(); ++j) { tmp.push_back({}); for(int k = 0; k < element[j].size(); ++k) { tmp[j].push_back(&element[j][k]); } } r1[i] = tmp; }
方式二:使用迭代器遍历map(更推荐)
其实遍历map用下标o1[i]并不是最优的,尤其是当键不是连续整数的时候(虽然你的代码用了i从0到size,但map的键不一定是连续的),用迭代器遍历更安全也更高效:
map<int, vector<vector<myStruct>>> o1; map<int, vector<vector<myStruct*>>> r1; for(const auto& pair : o1) { // 用范围for遍历,pair是键值对的引用 const auto& element = pair.second; // 直接取原始值的引用 vector<vector<myStruct*>> tmp; for(const auto& inner_vec : element) { // 内层也用范围for,更简洁 vector<myStruct*> inner_tmp; for(const auto& item : inner_vec) { inner_tmp.push_back(const_cast<myStruct*>(&item)); // 如果o1是const的话需要const_cast,否则直接&item // 如果o1不是const,这里可以写成inner_tmp.push_back(&item); } tmp.push_back(std::move(inner_tmp)); // 用move减少拷贝 } r1[pair.first] = std::move(tmp); // 同样用move优化 }
额外注意事项
- 确保
o1的生命周期至少和r1一样长,或者比r1更长,否则即使你取了原始数据的指针,当o1被销毁后,r1里的指针还是会失效。 - 如果后续
o1里的元素被修改(比如vector扩容导致内存重新分配),那之前存在r1里的指针也可能失效,因为vector扩容会把元素移到新的内存地址。如果有这种情况,你可能需要考虑改用std::shared_ptr来管理对象生命周期,或者让o1存储的就是指针类型。
内容的提问来源于stack exchange,提问作者John Tan
相关产品推荐
相关产品推荐

