在使用相似列表的堆栈中实现正确的(底流保护的)pop/peek方法时出现问题 < >我想用链表编写C++ POST的方法来完成我的C++作业。 让我先向您展示节点和列表类,然后告诉您问题: class Node { public: int data; Node* next; Node(int data, Node* next = 0) { this->data = data; this->next = next; } }; class List { private: Node* head; // no need for the tail when using the list for implementing a stack public: List() { head = 0; } void add_to_head(int data) { if(head == 0) { head = new Node(data); } else { head = new Node(data, head); } } Node* get_head() { return head; } // this deletes the head element and makes 'head' points to the node after it. void delete_head() { // storing the head so that we could delete it afterwards. Node* temp = head; // making the head point to the next element. head = temp->next; // freeing memory from the deleted head. delete(temp); } };

在使用相似列表的堆栈中实现正确的(底流保护的)pop/peek方法时出现问题 < >我想用链表编写C++ POST的方法来完成我的C++作业。 让我先向您展示节点和列表类,然后告诉您问题: class Node { public: int data; Node* next; Node(int data, Node* next = 0) { this->data = data; this->next = next; } }; class List { private: Node* head; // no need for the tail when using the list for implementing a stack public: List() { head = 0; } void add_to_head(int data) { if(head == 0) { head = new Node(data); } else { head = new Node(data, head); } } Node* get_head() { return head; } // this deletes the head element and makes 'head' points to the node after it. void delete_head() { // storing the head so that we could delete it afterwards. Node* temp = head; // making the head point to the next element. head = temp->next; // freeing memory from the deleted head. delete(temp); } };,c++,stack,stackunderflow,C++,Stack,Stackunderflow,现在是堆栈: class stack { private: List* list; public: stack() { list = new List(); flush(); } void push(int value) { list->add_to_head(value); } bool pop(int& value_to_fill) { if(is_empty()) {

现在是堆栈:

class stack
{
private: 
    List* list;

public:
  stack()
  {
      list = new List();
      flush();
  }
  void push(int value)
  {
      list->add_to_head(value);
  }
  bool pop(int& value_to_fill)
  {
      if(is_empty())
      {
        return false; // underflow...
      }

      value_to_fill = list->get_head()->data;

     // deleting the head. NOTE that head will automatically point to the next element after deletion 
     // (check out the delete_head definition)
     list->delete_head();

     return true; // popping succeed.
  }
  bool peek(int& value_to_fill)
  {
    if(is_empty())
    {
       return false;
    }
    value_to_fill = list->get_head()->data;
    return true;
  }
 // other stuff...
};
现在的问题是pop和peek,我只是觉得它们不方便。 pop和peek不应提供任何参数,但如果我这样做:

int peek()
{
  if(is_empty())
    // what should I do here?
  return list->get_head()->data;
}
int pop()
{
  if(is_empty())
    // same thing here.

  // deleting the tos then returning it.
  // I know this is not what the pop in the STL stack does, but I like it this way
    int tos = list->get_head()->data;
    list->delete_head();
    return tos;
}
我不知道发生下溢时该怎么办。 我不能只返回-1或0之类的,因为这看起来就像我弹出了-1或0(tos==-1或0)
有没有一种方法可以编写防下溢的pop/peek,而不必通过引用传递任何内容?

这是一个规范问题。有几种可能的解决方案:

  • 将堆栈不为空作为
    pop
    的先决条件。它是 客户确保这一点的责任(可能通过致电
    在弹出前为空()
    ),并且违反了前提条件 导致断言失败

  • 如果堆栈为空,则引发异常。这是最明显的 解决方案,但可能是最不普遍适用的

  • 不要让
    pop
    返回值(或者让它返回您的
    bool
    )。到 获取顶部元素时,您有一个单独的函数,
    tos()
    ,以及一个客户端 想要同时完成这两项任务,需要两个函数调用:
    x=s.tos();s、 pop()。
    例如,这就是标准所做的。在实践中,这往往是错误的
    首选方法,因为对于复制可以抛出的类型(例如。
    
    std::string
    ),不可能实现pop来返回值和 给予强有力的例外保证。(无论这是否是一个问题 这是另一个问题,但在特定情况下可能是一个问题,事实确实如此 标准中的选择背后的动机,其中没有流行音乐 函数返回一个值。)

最后,重要的是定义接口,所以 您的用户知道要期望什么

顺便说一句,您不需要在
add_to_head
中使用
if
。如果
头部==
NULL
,您将使用第二个参数调用构造函数
NULL
,因此在这两种情况下,您最好只传递
head

(我将跳过一个事实,即使用链表效率非常低 实现堆栈的方法,因为代码显然是一种学习
他们说异常很好。你不想用讨厌的列表来代替吗?@doublep:好吧,从我(从C#)知道你不能这样做:int peek(){try{return list->get_head()->data;}catch(…){}你会得到一个错误,说所有路径都必须返回某个东西。但是我只是尝试了C++,效果不错!它编译时没有任何错误。它不应该给我那个错误吗?@ VXEE,如果代码真的走了那个路径,C++中只有一个错误。编译器很难确定这一点,因此不需要错误消息。(这叫做未定义的行为。)说得再好不过了。但是,实现堆栈的最佳方法是什么?使用数组?是的,正如你所猜测的,我只是在链表上训练。@VeXe我通常会使用
std::vector
,使用
push_-back
pop_-back
back
来实现push、pop和tos。