类的析构函数中应该删除哪些内容 P>所以我已经做了一段时间的C++代码,我只是想知道在析构函数中应该删除基本链表中的哪些变量,不幸的是我目前不能就这个问题查阅我的C++手册。链表类如下所示: #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? } };

类的析构函数中应该删除哪些内容 P>所以我已经做了一段时间的C++代码,我只是想知道在析构函数中应该删除基本链表中的哪些变量,不幸的是我目前不能就这个问题查阅我的C++手册。链表类如下所示: #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? } };,c++,vector,destructor,C++,Vector,Destructor,这会转到链表的下一个节点并删除该节点,从而递归地从该点删除整个列表吗?另外,如果是这样的话,并且出于某种原因我选择实现它,那么在删除它之前,我是否必须检查next是否为nullptr,或者它是否没有什么区别 谢谢。基本上你应该 delete next 这就是你应该做的: 字符串和向量对象有它们自己的析构函数,由于该对象正在被析构函数 ,所以你甚至不必检查 如果next不是空指针,它将根据需要不断调用下一个节点的析构函数 只需删除它,就可以了。将调用类析构函数(它为空),然后调用成员对象析

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


谢谢。

基本上你应该

delete next 
这就是你应该做的:

  • 字符串
    向量
    对象有它们自己的析构函数,由于该对象正在被析构函数

  • ,所以你甚至不必检查

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


只需删除它,就可以了。

将调用类析构函数(它为空),然后调用成员对象析构函数

若成员不是对象,则不会调用析构函数

在您的示例中:

- List *next: pointer on List: no destructor called
- string sName: string object: destructor called
- vector<char> cvStuff: vector object: destructor called
-List*下一步:列表上的指针:未调用析构函数
-字符串sName:string对象:已调用析构函数
-向量对象:已调用析构函数
好消息:你无事可做。析构函数声明在这里甚至没有用处

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


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

理想情况下,不使用任何内容:使用智能指针:
std::unique\u ptr
std::smart\u ptr
boost::scoped\u ptr
,等等

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

    你打算在列表中间删除一些东西吗?如果是,则无法在析构函数中删除
  • 你打算分享尾巴吗?如果是,则需要引用计数的智能指针
可以删除nullptr(不做任何操作)。在本例中,您不应该删除sName和cvStuff,因为它们的作用域是有限的,因此会自动销毁

此外,如果这是一个可能会变大的列表,您可能需要手动销毁并取消分配
*next
。这是因为您不希望递归耗尽堆栈空间


此外,我建议将其分离为
列表
,这意味着数据结构和
列表节点
,这意味着元素。您的问题实际上显示了这种模糊性,即您不知道是删除析构函数中的
列表节点
还是
列表
。将它们分开可以解决这个问题。

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

{  // 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\uu
中没有发生任何特殊情况:它是一个简单标量类型的指针,因此代码不会自动对其执行任何操作

因此,在list类中,您唯一需要担心的是您的
下一个
成员:您需要确定它是否是“拥有”指针。如果它是“拥有”指针,则必须在析构函数中对对象调用
delete

或者,您可以利用“RAII”(资源获取是初始化)并使用对象包装指针,并提供一个析构函数,该析构函数将为您调用
delete

{  // scope
    std::unique_ptr<Node> ptr = std::make_unique<Node>(args);
}  // end scope -> ptr.~unique_ptr() -> delete -> ~Node()
在上述情况下,向量拥有节点,您绝对不应该在
节点
析构函数中调用
删除
,因为
节点
不是您要删除的

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

在这里,列表/节点是唯一有指向节点的指针的东西,因此在这个用例中,我们需要
Node::~Node
调用delete,否则我们就有漏洞。

Hmm,这只适用于const非尾部共享列表。对于非常量列表,您不能删除next:这将不允许删除元素O(1)。对于尾部共享列表,情况甚至更糟:您最终将删除所有其他元素。@对于递归数据结构,您确实应该使用引用计数智能指针,如
shared\u ptr
;其他任何事情都将是一场噩梦。节点共享数据结构要难得多,也许你可以在下次的问题中提到这一点。@AmiTavory:lorro不是问题所在asker@Ami:不是我的问题:),但每当我们实现(非学校)列表时,它们至少是const-tail共享:否则只需使用
std::list
。还要注意,如果你不共享,你甚至不能删除,而是允许在中间删除一个元素(在OP的解决方案中)。你在C++中经常遇到这种情况吗?这在Haskell、Scheme等中非常常见,但我个人从未在生产中见过。然而,基于共享的管理似乎是实现这一目标的途径。它试图同时成为列表节点和列表。名单是谁的?如果列表的尾部相同,您是否共享它们?你打算删除元素,还是只删除整个列表?@lorro,是的,从技术上讲,这是一个节点类,并且已经相应地进行了调整。定义共享尾部?另外,删除整个列表。在这种情况下,不要删除!否则,您将无法编写一个快速擦除操作,该操作将擦除列表中的任何给定元素。共享前向链表的尾部意味着,如果您知道两个列表的背面应该有相同的元素,则共享节点。Ve
std::vector<Node> nodes;
populate(nodes);

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