类的析构函数中应该删除哪些内容 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? } };
这会转到链表的下一个节点并删除该节点,从而递归地从该点删除整个列表吗?另外,如果是这样的话,并且出于某种原因我选择实现它,那么在删除它之前,我是否必须检查next是否为nullptr,或者它是否没有什么区别类的析构函数中应该删除哪些内容 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不是空指针,它将根据需要不断调用下一个节点的析构函数 只需删除它,就可以了。将调用类析构函数(它为空),然后调用成员对象析
谢谢。基本上你应该
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
是否拥有
-
你打算在列表中间删除一些东西吗?如果是,则无法在析构函数中删除
- 你打算分享尾巴吗?如果是,则需要引用计数的智能指针
*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));