1

我对堆栈顶部元素的引用感到困惑。

#include <iostream>
#include <stack>
using namespace std;

int main()
{
    stack<int> s;
    s.push(1);

    int        x = s.top();
    int&       y = s.top();
    const int& z = s.top();

    cout << x << '\t' << y << '\t' << z << endl;

    s.pop();
    s.push(2);

    cout << x << '\t' << y << '\t' << z << endl;
}
/* Output:
1       1       1
1       2       2
 */

我认为不应该更改对顶部元素的引用,但是在将新元素推送到堆栈后,引用引用的值会更改。

这对我来说很奇怪,因为如果类型不是int堆栈的类型,比如说它的类型MyClass(非常大的数据),有没有办法安全地引用旧的顶部元素?(因为我不想进行昂贵的复制操作)。

我猜这种行为可能是依赖于实现的,签名!

4

2 回答 2

3

如 C++11 标准(23.6.5.2 -stack定义)中所述

reference top() { return c.back(); }
const_reference top() const { return c.back(); }
...
void push(const value_type& x) { c.push_back(x); }
void push(value_type&& x) { c.push_back(std::move(x)); }
...
void pop() { c.pop_back(); }

在您使用默认底层容器的地方std::deque迭代器/引用失效规则指出(引用答案):

deque:擦除最后一个元素只会使迭代器和对被擦除元素的引用和过去的迭代器无效;擦除第一个元素只会使迭代器和对被擦除元素的引用无效;擦除任何其他元素会使所有迭代器和引用无效(包括过去的迭代器)[23.3.3.4/4]

通过使用std::stack::pop,您必须调用std::deque::pop_back()which ,如上所述,使先前返回的引用无效std::stack::top(随后调用std::deque::back())。因此,您永远不应该依赖这种行为,因为它是未定义的、不可移植的并且是错误的。

如果您想获得堆栈顶部的原始值,解决方案是复制顶部元素,而不是对其进行引用。也就是说,如果您想在将元素弹出堆栈后正确保留原始值。

于 2013-08-12T05:58:40.953 回答
2

在 pop() 之后,引用无效。由于 std::stack 的实现细节,输出显示了新推送的值 - 不要依赖它,它也可能是垃圾。

于 2013-08-12T05:41:53.530 回答