能否不弹出元素就引用/索引std::stack中的项?若不能该如何实现?
使用std::stack访问任意元素的问题及解决方案
能不能直接用std::stack访问任意元素?
不行。std::stack是STL里的适配器容器,设计初衷是严格遵循栈的LIFO(后进先出)特性,只对外暴露栈顶操作(top()获取栈顶引用、push()入栈、pop()出栈),没有提供索引访问、指针引用任意位置元素的接口。它的底层默认用std::deque实现,但刻意隐藏了底层容器的随机访问能力,所以没法直接不弹出就访问栈中间或栈底的元素。
针对虚拟机本地栈场景的解决方案
你的场景需要像汇编里那样通过rbp偏移访问栈变量,本质是需要支持随机访问的栈结构,这里给你三种可行方案:
1. 直接用std::vector/std::deque模拟栈
放弃std::stack,直接用支持随机访问的容器模拟栈操作,这是最直接的方案:
- 用
push_back()替代stack.push() - 用
pop_back()替代stack.pop() - 用
back()替代stack.top() - 直接通过索引
[index]访问任意位置的元素
对应你的场景示例:
#include <vector> #include <cstdint> std::vector<uint32_t> vm_stack; // 对应 mov DWORD PTR [rbp-4], 123 vm_stack.push_back(123); // 对应 mov DWORD PTR [rbp-8], 321 vm_stack.push_back(321); // 对应 add DWORD PTR [rbp-4], 1 // rbp-4对应栈顶前一个元素(每个元素4字节),索引为size()-2 vm_stack[vm_stack.size() - 2] += 1;
2. 封装自定义的VM栈类
如果想保留栈的语义(对外只暴露栈相关操作,同时支持随机访问),可以基于std::vector封装自己的栈:
#include <vector> #include <cstdint> class VMStack { private: std::vector<uint32_t> m_data; public: // 标准栈操作 void push(uint32_t val) { m_data.push_back(val); } void pop() { m_data.pop_back(); } uint32_t& top() { return m_data.back(); } const uint32_t& top() const { return m_data.back(); } // 支持随机访问,index=0是栈底,index=size()-1是栈顶 uint32_t& operator[](size_t index) { return m_data[index]; } const uint32_t& operator[](size_t index) const { return m_data[index]; } size_t size() const { return m_data.size(); } bool empty() const { return m_data.empty(); } };
使用时和示例的对应关系和上面一致,这种方式更符合虚拟机栈的语义,也方便后续扩展功能。
3. 继承std::stack暴露底层容器(不推荐)
如果一定要用std::stack,可以通过继承暴露它的底层保护成员c(底层容器对象),但这种方式依赖STL的实现细节,可移植性差,不推荐在生产代码里用:
#include <stack> #include <vector> #include <cstdint> template<typename T> class AccessibleStack : public std::stack<T, std::vector<T>> { public: // 暴露底层容器 using std::stack<T, std::vector<T>>::c; // 提供随机访问接口 T& at(size_t index) { return c[index]; } const T& at(size_t index) const { return c[index]; } }; // 使用示例 AccessibleStack<uint32_t> vm_stack; vm_stack.push(123); vm_stack.push(321); vm_stack.at(vm_stack.size() - 2) += 1;
总结
对于虚拟机本地栈这种需要随机访问栈元素的场景,直接用std::vector或封装自定义栈类是最优选择,完全满足你通过偏移访问栈变量的需求,比强行用std::stack要灵活得多。
内容的提问来源于stack exchange,提问作者Kladskull
相关产品推荐
相关产品推荐

