【问题标题】:Programming error in allocating new stack分配新堆栈时出现编程错误
【发布时间】:2012-08-17 17:53:18
【问题描述】:

我正在编写一个程序来实现一个堆栈,它像现实世界的堆栈一样工作,这意味着当堆栈的大小达到阈值时它会倒塌,因此需要创建一个新堆栈来插入该新元素。

以下是我的程序:

#include <iostream>
#include<vector>
#include<stack>

using namespace std;

class stack_of_plates
{
   vector<stack<int> > stacks;
   unsigned int stack_size;
   public:
   stack_of_plates(unsigned int size=100)
   {
       stack_size=size;
   }

   void push(int data)
   {
       if(stacks.empty())
       {
           stack<int> *sptr= new stack<int>; //on debugging Segmentation fault at thisline
           stacks.push_back(*sptr);
       }

       vector<stack<int> >::iterator it=stacks.end();
       if(it->size()==stack_size)
       {
           stack<int> *sptr= new stack<int>; //on debugging Segmentation fault at thisline
           stacks.push_back(*sptr);
       }
       it->push(data);
   }

   void pop()
   {
       if(stacks.empty())
       {
           cout<<"\nEmpty Stack";
           return ;
       }
       vector<stack<int> >::iterator it=stacks.end();
       if(it->empty())
       {
           it--;
       }
       it->pop();
   }
   int top()
   {
       if(stacks.empty())
       {
           cout<<"\nEmpty Stack";
           return 0;
       }
       vector<stack<int> >::iterator it=stacks.end();
       if(it->empty())
       {
           it--;
       }
       return it->top();
   }
};


int main()
{
   stack_of_plates ss;
   ss.push(1);
   ss.push(2);
   cout<<ss.top();
   return 0;
}

在编译时不会出现错误或警告。但是程序因异常错误而终止。 在调试它给出的分段错误错误指示分配新堆栈的问题。 请帮助我在分配新堆栈时应该如何更改我的代码。请帮我消除这个错误。

【问题讨论】:

  • 究竟什么是“编程错误”?
  • 不,那是不是他们所说的“堆栈指针”...
  • 这完全是假的:stack&lt;int&gt; *sptr= new stack&lt;int&gt;; stacks.push_back(*sptr);。它应该是stacks.push_back(stack&lt;int&gt;());,或stacks.emplace_back();,或stacks.resize(stacks.size() + 1);
  • 我的问题:我知道我在分配新堆栈时犯了错误。这就是为什么我在这里张贴寻求帮助的原因。请帮助我在我评论的行中应该写什么。
  • 两点:如果你在堆上分配堆栈然后像你一样推送它们,你将有内存泄漏,因为你将 copy 推送到堆栈上。其次是generic_container.end()不返回generic_container中的最后一个条目,所以在使用迭代器之前必须使用it--

标签: c++ stack


【解决方案1】:

代码有很多问题,所以很难说哪一个是你问题的直接原因。您需要将它们一一清理,然后重新测试。如果您仍有问题,请在此处发布您的新代码。

这里是列表:

  1. 使用 new 分配的内存泄漏。由于您有一个堆栈向量,您需要做的就是调整向量的大小并分配一个新的堆栈。所以

    stacks.resize(stacks.size() + 1);

    而不是

    stack&lt;int&gt; *sptr= new stack&lt;int&gt;; stacks.push_back(*sptr);

  2. vector.end() 返回一个迭代器,该迭代器指向最后一个元素之后的元素,这就是为什么@Joachim 建议您需要在使用之前减少迭代器。

    李>
  3. 当您检查是否将存储转移到新堆栈时出现逻辑错误 - 检查最后一个堆栈的大小是否为最大值,然后创建一个新堆栈,然后继续推旧堆栈。

我希望这会有所帮助。

【讨论】:

  • 非常感谢你们。我已经意识到我的错误。唯一的问题是我使用 .end() 而不是递减迭代器。我已经纠正了它,它现在工作正常。我只是想知道 Mike 的评论为什么不建议使用迭代器将数据推送到向量的元素中。
【解决方案2】:

stacks.end(); 指的是向量末尾之后的(不存在的)元素。你不能取消引用它;这样做会导致未定义的行为,可能是分段错误。

不太清楚你在做什么,但如果你想要最后一个元素的迭代器,那么要么递减它:

vector<stack<int> >::iterator it=stacks.end();  // points past the end
--it;                                           // points to last element

或使用反向迭代器(在这种情况下,您使用++ 而不是-- 在序列中向后移动):

vector<stack<int> >::reverse_iterator it=stacks.rbegin();

将元素添加到向量可以使其无效,因此push() 末尾的it-&gt;push_back(data) 不正确。您可以避免在此处使用迭代器:

void push() {
    if (stacks.empty() || stacks.back().size()==stack_size) {
        // See below for explanation of this change
        stacks.push_back(stack<int>());
    }
    stacks.back().push(data);
}

pop() 中,如果最后一个堆栈为空,您可能想要删除它;否则,您最终会得到两个空堆栈,并且您的代码将错误地尝试从其中一个堆栈中尝试 pop。同样,这样做可能会导致分段错误或其他未定义的行为。你可能想要这样的东西:

void pop() {
    if (stacks.empty()) {
        cout<<"\nEmpty Stack";
        return ;
    }
    stacks.back().pop();
    if (stacks.back().empty()) {
        stacks.pop_back();
    }
}

现在我们已经建立了最后一个堆栈永远不会为空的不变量,top 可以简单一点:

int top() {
    if (stacks.empty()) {
        cout<<"\nEmpty Stack";
        return 0;
    }
    return stacks.back().top();
}

此外,您通常不希望使用new 创建对象,尤其是在这种情况下,您将对象的副本放入向量中,然后丢弃指针,从而泄漏分配的内存。您可以像这样向向量添加一个空堆栈:

stacks.push_back(stack<int>());

有时(但不是在这种情况下)您可能希望将指向已分配对象的指针存储在容器中;在这种情况下,要么记住在从容器中删除它们时删除它们,要么存储智能指针,例如std::unique_ptr。但在这种情况下,只需存储对象即可。

【讨论】:

    【解决方案3】:

    std::stack&lt;int&gt; 已经具有您在示例中显示的功能,因此不需要std::vector&lt; std::stack&lt;int&gt; &gt;。通过推送和弹出std::stack&lt;int&gt;,您可以避免代码中的大部分问题。没有理由将std::stack&lt;int&gt; 限制为stack_size

    除此之外,当您需要容器中的最后一个条目时,请使用 back() 而不是 end()

    【讨论】:

      猜你喜欢
      • 2019-09-30
      • 1970-01-01
      • 2021-08-05
      • 2013-04-16
      • 1970-01-01
      • 2017-02-17
      • 1970-01-01
      • 2017-08-15
      相关资源
      最近更新 更多