所以我已经有一段时间了,因为我已经完成了任何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?
}
};
我也很好奇,如果在析构函数中我打电话
delete next;
是否会转到链接列表的下一个节点并删除该节点,从而以此方式从该点递归删除整个列表?另外,如果是这种情况并且由于某种原因我选择实现它,我是否必须在删除之前检查next是否为nullptr还是不会产生影响?
谢谢。
答案 0 :(得分:1)
理想情况下,没有:使用智能指针:std::unique_ptr<>
,std::smart_ptr<>
,boost::scoped_ptr<>
等。
否则,您删除拥有本机指针的内容。 next
拥有吗?
可以删除nullptr(什么都不做)。在这个例子中,你不应该删除sName和cvStuff,因为它们是作用域的,因此会自动销毁。
此外,如果这将是一个可能变大的列表,您可能想要销毁&amp;手动释放*next
。这是因为您不希望通过递归耗尽堆栈空间。
此外,我建议将此分隔为List
,表示数据结构,ListNode
表示元素。您的问题实际上表明了这种含糊不清,您不知道自己是否正在删除析构函数中的ListNode
或List
。将它们分开解决了这个问题。
答案 1 :(得分:1)
具有自动生命周期的对象在超出范围时调用它的析构函数:
{ // 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_
没有什么特别的事情发生:它是一个简单的标量类型的指针,所以代码不会自动执行任何操作。
因此,在您的列表类中,您唯一需要担心的是您的next
成员:您需要确定它是否属于&#34;拥有&#34;指针与否。如果是拥有&#34;拥有&#34;然后你必须在析构函数中的对象上调用delete
。
或者,您可以利用&#39; RAII&#39; (资源获取是初始化)并使用对象来包装指针并提供将为您调用delete
的析构函数:
{ // scope
std::unique_ptr<Node> ptr = std::make_unique<Node>(args);
} // end scope -> ptr.~unique_ptr() -> delete -> ~Node()
unique_ptr
是一个纯粹拥有的指针,另一个替代方案可能是shared_ptr
,它使用引用计数,以便当你没有时,底层对象只有delete
d对象的任何剩余shared_ptr
。
如果您将next
的实际地址保留在其他位置,您会认为您的Node
指针是非拥有指针:
std::vector<Node> nodes;
populate(nodes);
list.insert(&nodes[0]);
list.insert(&nodes[1]);
// ...
在上面的例子中,向量拥有节点,你绝对不应该在delete
析构函数中调用Node
,因为Node
不是你要删除的。
list.insert(new Node(0));
list.insert(new Node(1));
这里,列表/节点是唯一具有指向节点的指针,因此在这个用例中我们需要Node::~Node
来调用delete或者我们有泄漏。
答案 2 :(得分:0)
基本上你应该
delete next
那就是你应该做的一切:
string
和vector
个对象都有自己的析构函数,并且由于此对象正在被破坏,theirs will be called。
Deleting a null pointer is not a problem,所以您甚至不必检查。
如果next
不是空指针,它会根据需要继续调用下一个节点的析构函数。
只需将其全部删除即可。
答案 3 :(得分:0)
将调用您的类析构函数(它为空),然后调用成员对象析构函数。
如果member不是对象,则不会调用析构函数。
在你的例子中:
- List *next: pointer on List: no destructor called
- string sName: string object: destructor called
- vector<char> cvStuff: vector object: destructor called
好消息:你无事可做。析构函数声明在这里甚至没用。
如果在析构函数中删除next
,则删除项目将删除列表中的所有其他项目:不是很有用。
(而你的List
对象应该被称为Node
)。 List是所有节点的链接结果,由您创建的第一个节点保存。