将 std::stack 复制到 std::vector
Posted
技术标签:
【中文标题】将 std::stack 复制到 std::vector【英文标题】:Copy std::stack into an std::vector 【发布时间】:2011-05-19 18:17:39 【问题描述】:标准是否保证以下代码可以工作(假设 st 不为空)?
#include <vector>
#include <stack>
int main()
extern std::stack<int, std::vector<int> > st;
int* end = &st.top() + 1;
int* begin = end - st.size();
std::vector<int> stack_contents(begin, end);
【问题讨论】:
【参考方案1】:是的。
std::stack
只是一个容器适配器。
你可以看到.top()
实际上是(§23.3.5.3.1)
reference top() return c.back();
其中c
是容器,在本例中是std::vector
也就是说你的代码基本翻译成:
extern std::vector<int> st;
int* end = &st.back() + 1;
int* begin = end - st.size();
std::vector<int> stack_contents(begin, end);
由于std::vector
保证是连续的,所以应该没有问题。
但是,这并不意味着这是一个好主意。如果您需要像这样使用“hacks”,这通常表明设计不佳。您可能想从一开始就使用std::vector
。
【讨论】:
+1 您可以编辑已删除的回复并取消删除。 我明白了,以后会这样做的。 一些算法规定使用堆栈,并且需要在结束时以其他某种(通常是数组或向量)形式(例如,DAG 的拓扑排序)返回堆叠的元素。恕我直言,使用标准堆栈适配器而不是自己滚动是首选。最后手动从堆栈中弹出所有元素比必要的要慢,并且考虑到这里的代码完全兼容和正确,我认为它没有任何问题。在需要时将其保存在工具箱中是一个很好的模式。【参考方案2】:C++03 仅保证 std::vector
具有连续元素 (23.4.1)。在 C++1x 中,这也将扩展到 std::string
(defect #530)。
【讨论】:
哇,我从来不知道 string 没有这样的保证。有趣,谢谢。支持,虽然这与我的问题无关【参考方案3】:是的,这是有保证的。向量保证使用连续存储,因此您的代码可以工作。虽然它有点笨拙 - 如果有人更改堆栈的底层容器类型,您的代码将继续编译而不会出错,但运行时行为将被破坏。
【讨论】:
【参考方案4】:不幸的是,我没有参考标准来支持这一点,但我猜它可能出错的方式并不多:
将std::vector<int>
指定为容器类型意味着元素必须存储在std::vector<int>
中。
st.top()
必须返回对底层容器中元素的引用(即std::vector<int>
中的元素。由于对容器的要求是支持back()
、push_back()
和pop_back()
,我们可以合理假设top()
返回对向量中最后一个元素的引用。
end
因此指向最后一个元素之后的一个元素。
start
因此指向开头。
结论:除非假设是错误的,否则它必须有效。
编辑:鉴于其他答案对标准的引用,假设是正确的,所以它有效。
【讨论】:
【参考方案5】:根据this page,std::stack
使用容器类来存储元素。
我猜你的建议只有在容器以线性方式存储其元素时才有效 (std::vector
)。
默认情况下,std::stack
使用 std::deque
,据我所知,它不符合此要求。但是,如果您将 std::vector
指定为容器类,我看不出它不应该工作的原因。
【讨论】:
这就是为什么他指定std::vector<int>
作为我猜的容器类型:)
@sgolodetz:刚刚意识到这一点;)我现在还没有完全清醒。【参考方案6】:
编辑:最初的声明已被编辑,标准实际上确实为堆栈适配器提供了完整的定义,没有任何东西留给实施者。查看最佳答案。
您需要一个具有 push 和 pop 方法的容器,并允许您检查容器中任何位置的元素并使用 std::vector
进行存储。标准模板库中有这样一个容器
它被称为std::vector
。
std::stack
仅用于束缚目的
【讨论】:
以上是关于将 std::stack 复制到 std::vector的主要内容,如果未能解决你的问题,请参考以下文章
预期的枚举`std::result::Result`,发现结构`std::vec::Vec`。