0

当我实现包含节点的堆栈的pop()和析构函数时,我应该在删除节点本身之前删除节点->数据还是应该只删除节点并让创建节点​​->数据的调用者删除节点->数据?如果让调用者这样做,调用者应该何时以及如何删除数据?它应该以这种方式调用:{data = stack.top(); 删除数据;stack.pop();}?

我没有看到任何删除 node->data 的代码,无论是在 pop() 的实现中还是在调用者函数中。这就是为什么我很困惑。

在这里我复制了我使用链接列表实现的堆栈。请看一下我的问题的 pop() 和 ~stack() 的注释。谢谢你的帮助。

typedef struct Node_t{
    struct Node_t* next;
    void* data;
}Node; 

class stack {
public: 
    stack(): _head(null), _size(0){}
    ~stack();
    void push(void* data);
    void pop();
    void* top();
    bool empty();
    stack(const stack& original);
    stack& operator=(const stack& original);    
private:
    Node* _head;    
    int _size;  
};
stack::~stack{
 Node* next = null;
 while(_head){
      next = _head->next;
      //should delete _head->_data???
      delete _head;                     
      _head = next;
 }
 _size = 0;
}
void stack::push(void* data){
    Node* elem = new Node;
    elem->data = data; 
    elem->next = _head;
   _head = elem;
    _size++;
}    

void stack::pop(){
Node* next = NULL;
if (_head) {
   next = _head->next;
   //should delete _head->_data???
   delete _head;
   _head = next;        
   _size--;
}
}    

void* stack::top() const{
if (_head) {
   return _head->_data;
}        
}

bool stack::empty(){
   if(_size>0) return false;
   else return true;
}
4

2 回答 2

2

您的数据是指向其他地方的指针。这里的策略是:在堆栈外创建一个数据对象,并将数据指针压入堆栈。因此,通过对称性,删除数据的控制也应该存在于您的堆栈之外。如果您不需要它,则需要显式删除它。例如:

stack s;
char mydata[] = {'a','b','c'};
s.push((void*)mydata);
//do things
s.pop();
delete [] mydata;

如果你真的想控制堆栈内部的数据(通过它可能不是一个好主意,假设你的数据可能在其他地方使用),那么还有一个问题。因为数据类型是 void* 并且您可能无法按原样“安全地”删除它。看到这个线程删除一个空指针是否安全?

于 2013-06-27T22:14:26.947 回答
1

这个答案有几个部分:

  1. 对于实际编程,没有理由在标准库已经提供这些数据结构的情况下构建自己的数据结构。

  2. 如果您必须构建自己的数据结构作为学习练习,原则上您可以拥有任何您希望的分配和删除语义。

  3. 但是,如果您必须构建自己的堆栈,我强烈建议您遵循与标准库堆栈相同的语义,它使用复制和引用语义来避免在用户代码中显式分配和删除的需要。

遵循标准库语义提高了一致性,减少了理解接口的认知负担,并大大减少了内存泄漏的机会。

于 2013-06-27T22:05:44.290 回答