6.5 带有构造函数和析构函数的Stack
重新实现含有构造函数和析构函数的链表(在Stack内),看看使用new和delete时,构造函数和析构函数怎样巧妙地工作。这是修改后的头文件:
不仅Stack有构造函数与析构函数,而且被嵌套的类Link也有。
构造函数Link:Link()只是简单地初始化data指针和next指针,所以在Stack:push()中下面这行:
不仅为一个新的链表分配内存(用第4章中介绍的关键字new动态创建对象),而且也巧妙地初始化该对象的指针成员。
读者也许想知道Link的析构函数为什么不做任何事情,尤其是为什么不删除data指针?这里存在两个问题:在第4章引入Stack的地方,指出了如果void指针指向一个对象的话,就不能正确地将其删除(这种情况将在第13章中说明)。但是,除此之外,如果Link的析构函数删除data指针,pop()将最终返回一个指向被删除对象的指针,很明显,这会引起错误。有时这被看做是所有权(ownership)问题:Link和Stack仅仅存放指针,但它们不负责清除这些指针。这意味着必须非常小心,要知道由谁来负责这种工作。例如:如果不做pop()而删除Stack中的所有指针,它们就不会自动被Stack的析构函数清除。这种问题不是独立的,它会导致内存泄漏,所以知道谁来负责清除一个对象,对于一个程序是成功还是失败来说是很关键的—这就是为什么如果Stack对象销毁时不为空,Stack:~Stack()就会打印出错误信息的原因。
因为分配和清除Link对象的实现隐藏在类Stack中,它是内部实现的一部分,所以在测试程序中看不到它运行的结果,尽管从pop()返回的指针由我们负责删除。
既然这样,textlines中的所有行被弹出和删除,但是如果不出现这些操作的话,就会得到由require()带回的信息,这些信息表明这里有内存泄漏。