在 class 的析构函数中应删除的所有内容

What all should be deleted in the destructor of a class

所以我已经有一段时间没有完成任何 C++ 编码了,我只是想知道应该在析构函数中删除基本链表中的哪些变量,不幸的是我目前无法查阅我的 C++ 手册事。链表 class 如下所示:

#include <string>
#include <vector>

class Node
{
    Node *next;
    string sName;
    vector<char> cvStuff;

    Node(string _s, int _i)
    {
        next = nullptr;
        sName = _s;

        for (int i = 0; i < _i; i++)
        {
            cvStuff.insert(cvStuff.end(), '_');
        }
    }

    ~Node()
    {
         //since sName is assigned during runtime do I delete?
         //same for cvStuff?
    }
};

我也很好奇,如果在我调用的析构函数中

delete next;

是否会转到链表的下一个节点并删除该节点,从而递归地从该点删除整个列表?另外,如果是这种情况并且我出于某种原因选择实现它,我是否必须在删除它之前检查 next 是否为 nullptr 或者它不会有所作为吗?

谢谢。

基本上你应该

delete next 

这就是你应该做的:

  • stringvector对象有自己的析构函数,由于这个对象正在被析构,theirs will be called.

  • Deleting a null pointer is not a problem,所以你甚至不必检查它。

  • 如果next不是空指针,它将根据需要继续调用下一个节点的析构函数。

删掉就行了

将调用您的 class 析构函数(它是空的),然后调用成员对象的析构函数。

如果成员不是对象,则不调用析构函数。

在你的例子中:

- List *next: pointer on List: no destructor called
- string sName: string object: destructor called
- vector<char> cvStuff: vector object: destructor called

好消息:你无事可做。析构函数声明在这里甚至没有用。

如果您在析构函数中删除 next,则删除一个项目将删除列表中的所有其他项目:不是很有用。

(你的 List 对象应该被称为 Node)。列表是所有节点的链接结果,由您创建的第一个节点持有。

理想情况下,什么都不做:使用智能指针:std::unique_ptr<>std::smart_ptr<>boost::scoped_ptr<> 等。

否则,您删除拥有的本机指针。 next 是否拥有?

  • 您打算删除列表中间的内容吗?如果是,则不能在析构函数中删除。
  • 你打算分享尾巴吗?如果是,则需要 reference-counted 个智能指针。

可以删除 nullptr(什么都不做)。在示例中,您不应该删除 sName 和 cvStuff,因为它们在范围内,因此会自动销毁。

此外,如果这将是一个可以变大的列表,您可能需要手动销毁和释放 *next。这是因为您不想通过递归 运行 出栈 space。

此外,我建议将其分为List,表示数据结构和ListNode,表示元素。你的问题实际上表明了这种歧义,你不知道你是在析构函数中删除 ListNode 还是 List 。将它们分开可以解决这个问题。

具有自动生命周期的对象在超出范围时会调用其析构函数:

{  // scope
    std::string s;
}  // end scope -> s.~string()

动态对象(使用 new 分配)不会调用其析构函数,除非对其调用 delete

对于成员变量,范围是对象的生命周期。

struct S {
    std::string str_;
    char* p_;
};

int main() {  // scope
    {  // scope
        S s;
    }  // end scope -> s.~S() -> str_.~string()
}

请注意,上面的 p_ 没有发生任何特殊情况:它是一个简单标量类型的指针,因此代码不会自动对其执行任何操作。

所以在你的列表 class 中你唯一需要担心的是你的 next 成员:你需要决定它是否是一个 "owning" 指针。如果它是一个 "owning" 指针,那么您必须在析构函数中对对象调用 delete

或者,您可以利用 'RAII'(资源获取即初始化)并使用 对象 包装指针并提供将调用 [=15= 的析构函数] 给你:

{  // scope
    std::unique_ptr<Node> ptr = std::make_unique<Node>(args);
}  // end scope -> ptr.~unique_ptr() -> delete -> ~Node()

unique_ptr 是一个纯粹拥有的指针,另一种选择可能是 shared_ptr,它使用引用计数,这样底层对象只有 deleted 当你没有对象的任何剩余 shared_ptrs。

如果您将 Node 的实际地址保存在其他地方:

,您会认为您的 next 指针是非拥有指针
std::vector<Node> nodes;
populate(nodes);

list.insert(&nodes[0]);
list.insert(&nodes[1]);
// ...

在上面的例子中,vector 拥有节点,你绝对不应该在 Node 析构函数中调用 delete,因为 Node 不是你要删除的。

list.insert(new Node(0));
list.insert(new Node(1));

这里,list/Nodes 是唯一具有指向节点的指针的东西,所以在这个用例中我们需要 Node::~Node 来调用 delete 否则我们有泄漏。