为何指针赋值会导致看似无关的区间值意外变化?
双指针处理区间问题时的意外值变化分析
我尝试用双指针(double pointers)解决区间问题,核心思路是在unordered_map中存储指向Interval结构体的双指针,无需遍历map即可更新区间。但使用双指针时出现了意外的区间值变化:在代码的HERE 1和HERE 2标记之间,(*(it_pre->second))->word的值发生了改变,这段时间我仅创建了一个新的、无关的Interval,无法理解原因。
问题代码
#include <iostream> #include <vector> #include <utility> #include <unordered_map> using namespace std; int main() { vector<pair<int, char>> sequence = { {0,'a'}, {1,'-'}, {2,'b'}, {3,'c'}, {4,'-'}, {5,'d'}, {6,'e'}, {7,'-'}, {8,'f'}, {10,'g'}, {11,'-'}, {12, '-'} }; struct Interval { string word; bool startH; bool endH; Interval(string word) : word(word), startH(false), endH(false) {} }; Interval* hyphen = new Interval("-"); Interval** hPtr = ‐ auto consolidate = [&hPtr](Interval**& left, Interval**& right) { //cout << "\t(" << (*left)->word << " " << (*right)->word << ")" << endl; if (left == hPtr && right == hPtr) return; if (left == hPtr) { (*right)->startH = true; } else if (right == hPtr) { (*left)->endH = true; } else { (*right)->startH = (*left)->startH; (*right)->word = (*left)->word + (*right)->word; (*left) = (*right); } if ((*right)->startH && (*right)->endH) { cout << "RESULT: " << (*right)->word << endl; } else if ((*left)->startH && (*left)->endH) { cout << "RESULT: " << (*left)->word << endl; } }; unordered_map<int, Interval**> intervals; for (auto pair : sequence) { int index = pair.first; char c = pair.second; cout << "----" << index << ", " << c << "-----" << endl; int preIndex = index - 1; int postIndex = index + 1; auto it_pre = intervals.find(preIndex); auto it_post = intervals.find(postIndex); //HERE 1 //if (it_pre != intervals.end()) cout << (*(it_pre->second))->word << endl; Interval** currentIntervalPtr; if (c == '-') { currentIntervalPtr = hPtr; } else { Interval* currentInterval = new Interval(string(1, c)); currentIntervalPtr = ¤tInterval; } //HERE 2 //if (it_pre != intervals.end()) cout << (*(it_pre->second))->word << endl; if (it_pre != intervals.end()) { Interval** prePtr = it_pre->second; //cout << "PRE: <" << (*currentIntervalPtr)->word << ", " << (*prePtr)->word << ">>" << endl; consolidate(prePtr, currentIntervalPtr); } if (it_post != intervals.end()) { Interval** postPtr = it_post->second; //cout << "POST: <" << (*currentIntervalPtr)->word << ", " << (*postPtr)->word << ">>" << endl; consolidate(currentIntervalPtr, postPtr); } intervals[index] = currentIntervalPtr; } return 0; }
问题根源分析
问题出在非'-'字符的处理分支:
else { Interval* currentInterval = new Interval(string(1, c)); currentIntervalPtr = ¤tInterval; }
这里的currentInterval是栈上的局部变量,在for循环的每次迭代中,栈帧会重复使用这块内存空间。当你把¤tInterval(栈变量的地址)存入unordered_map后,下一次迭代创建新的currentInterval时,会直接覆盖这块栈内存,导致之前存在map里的指针指向的内容被意外修改——这就是HERE 1和HERE 2之间值莫名变化的核心原因。
除此之外,这段代码还存在两个严重问题:
- 野指针风险:栈变量在迭代结束后会被销毁,map中存储的指针会变成野指针,后续访问会触发未定义行为。
- 内存泄漏:
new出来的Interval对象没有被释放,会造成内存泄漏。
修复建议
- 避免存储栈指针:不要把指向栈变量的指针存入容器,改为在堆上分配指针变量,比如:
else { // 在堆上分配指针,避免栈内存覆盖 Interval** currentIntervalPtr = new Interval*(new Interval(string(1, c))); }
- 简化指针结构:你的场景不需要双指针,直接使用
unordered_map<int, Interval*>存储单指针即可,大幅降低复杂度。 - 使用智能指针:改用
std::unique_ptr或std::shared_ptr管理内存,自动避免内存泄漏和野指针问题。
内容的提问来源于stack exchange,提问作者William Convertino
相关产品推荐
相关产品推荐

