问题 将std :: stack复制到std :: vector中


标准是否保证以下代码可以正常工作(假设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);
}

5106
2017-12-03 13:32


起源



答案:


是。

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 保证是连续的应该没有问题。

但是,这并不意味着这是一个好主意。如果你需要像这样使用“黑客”,它通常是糟糕设计的一个指标。你可能想用 std::vector 从一开始就。


9
2017-12-03 13:42



+1您可能刚刚编辑了已删除的回复并取消删除。 - John Dibling
我明白了,将来会做到这一点。 - ronag
这是一个好奇的问题......不是真正的代码:) - Armen Tsirunyan
@Armen:很高兴听到它:) - Stuart Golodetz


答案:


是。

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 保证是连续的应该没有问题。

但是,这并不意味着这是一个好主意。如果你需要像这样使用“黑客”,它通常是糟糕设计的一个指标。你可能想用 std::vector 从一开始就。


9
2017-12-03 13:42



+1您可能刚刚编辑了已删除的回复并取消删除。 - John Dibling
我明白了,将来会做到这一点。 - ronag
这是一个好奇的问题......不是真正的代码:) - Armen Tsirunyan
@Armen:很高兴听到它:) - Stuart Golodetz


只要 std::vector 由C ++ 03保证具有连续元素(23.4.1)。在C ++ 1x中,这将扩展到 std::string 以及(缺陷#530)。


5
2017-12-03 13:49



哇,我从来不知道字符串没有这样的保证。有意思,谢谢。 Upvoting,虽然这与我的问题无关 - Armen Tsirunyan


是的,它是有保证的。保证向量使用连续存储,因此您的代码将起作用。虽然它有点笨拙 - 如果有人更改了堆栈的基础容器类型,您的代码将继续编译而不会出现错误,但运行时行为将被破坏。


2
2017-12-03 13:42





不幸的是,我没有参考标准来支持这个问题,但我认为没有多少方法可以解决这个问题:

  • 指定 std::vector<int> 因为容器类型意味着元素必须存储在一个 std::vector<int>
  • st.top() 必须返回对底层容器中元素的引用(即,中的元素) std::vector<int>。由于对容器的要求是它支持的 back()push_back() 和 pop_back(),我们可以合理地假设 top() 返回对向量中最后一个元素的引用。
  • end 因此指向一个过去的最后一个元素。
  • start 因此指向开头。

结论:除非假设错误,否则它必须有效。

编辑:鉴于另一个答案是对标准的引用,假设是正确的,所以它有效。


1
2017-12-03 13:43





根据 这一页std::stack 使用容器类来存储元素。

我猜你的建议只有当包含者以线性方式存储其元素时才有效(std::vector)。

默认情况下 std::stack 用一个 std::deque 据我所知,这不符合这个要求。但是,如果你指定一个 std::vector 作为一个容器类,我看不出它为什么不起作用的原因。


1
2017-12-03 13:44



这就是他指定的原因 std::vector<int> 作为容器类型我猜:) - Stuart Golodetz
@sgolodetz:刚刚意识到这一点;)我现在还没有完全清醒过来。 - ereOn
说实话,我第一次撇去它,差点错过了...... - Stuart Golodetz


编辑:初始语句编辑,标准实际上确实提供了堆栈适配器的完整定义,没有任何留给实现者。看到最佳答案。

您需要一个具有push和pop方法的容器,并允许您检查容器中任何位置的元素并使用 std::vector 用于存储。标准模板库中有这样的容器

它被称为 std::vector

使用 std::stack 仅用于束缚目的


-2
2017-12-03 13:41