2013-06-27 38 views
0

当我实现pop()和析构函数的堆栈持有节点,我应该删除node->数据之前删除节点本身或者我应该删除让创建节点​​ - >数据的调用者删除节点 - >数据?如果让主叫方这样做,主叫方何时以及如何删除数据?它应该以这种方式调用:{data = stack.top();删除数据; stack.pop();}?在哪里删除节点 - >日期在链接列表实现的堆栈

我还没有看到任何删除节点 - >数据的代码,既不在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; 
} 

回答

2

你的数据是一个指向其他地方的指针。这里的策略是:你在堆栈外创建一个数据对象,并将数据指针推入你的堆栈。所以,通过对称性,删除数据的控制也应该存在于你的堆栈中。如果你不需要它,你需要明确地删除它。例如:

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

如果你真的想控制栈中的数据(通过它可能不是一个好主意,假设您的数据可能在其他地方使用),也有问题。由于数据类型是无效的*,因此您可能无法'安全地'删除它。看到这个线程Is it safe to delete a void pointer?

+0

+1:我同意这是基于现有的'push()'语义对'pop()'的一个好方法。尽管在引用语义可用的情况下,我不能立即想到一个例子,其中现有的'push()'注释是整个设计的最佳选择。 – Simon

+0

谢谢你的例子。 – user389955

1

有几个部分,以这样的回答:

  1. 对于实际的编程,没有理由永远建立在那里这些数据结构已经由标准库提供你自己的数据结构。

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

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

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

+0

这是为了学习。我试图让接口与std :: stack相同,只是我没有使用模板,比如使用push(const T&data),因为我不想让代码复杂化。但似乎我最好根据你的建议使用通过引用(T&数据)的模板,而不是传递指针(void * data)。 Thx – user389955

+0

我刚刚读了std :: stack并发现数据不是通过引用传递的,它被复制到堆栈。请参阅http://www.daniweb.com/software-development/cpp/threads/301165/stack-implementation-code-using-stl。在第60行 - >第64行 - >第52行,该项目将被复制到nodeValue。如果nodevalue的结构很复杂,则复制代价很高。 – user389955

+0

如果您将指针的副本推送到节点数据,这非常便宜,而且这些语义明确地将分配和删除内存的责任放在用户的代码中,这是您希望完成的任务。 – Simon