假设我们有一个名为Node的类,它是单链表的构建块.@H_403_3@
class Node { int data; Node* next; }
事实1:局部变量(非静态)将在相应函数退出时被销毁.@H_403_3@
问题1:情况如何打击:@H_403_3@
Node* func() { Node n; Node* ptr=&n; return n; }
节点n会被破坏吗?或者我们必须使用new运算符来创建节点并返回指向堆内存的指针.如果两种方式都有效,哪种方法更好?@H_403_3@
问题2:如何为节点类编写析构函数? (我在stackOverflow上找到了一些类似的问题,但那些答案集中在链表的析构函数上.我已经得到了那个部分.我想要的只是Node类的析构函数).@H_403_3@
—————————————感谢大家!我知道了 – – – – – – – – – – – – – – – – – – @H_403_3@
感谢所有给我建议或指出我的错误的人.我想我得到了答案.以下是我从你的答案中得到的一个注释,这真的打败了我的困惑.@H_403_3@
>从函数返回堆栈内存地址不是一个好习惯,因为它会导致未定义的行为.
>返回堆内存是可以的,但我们必须处理对象的破坏.
>另一种方法是返回一个对象,从复制构造函数中受益.@H_403_3@
解决方法
Node* func() { Node n; Node* ptr=&n; return n;}
您的代码创建一个本地Node实例(在堆栈上),然后返回其地址.当函数返回时,作为局部变量的Node实例将被销毁.函数返回的地址现在指向具有未定义内容的某些内存,并且任何取消引用此指针的尝试都将导致未定义的行为.@H_403_3@
为了创建节点,您实际上需要调用Node构造函数.如何返回结果与调用构造函数的方式有关.@H_403_3@
>您可以按照尝试返回指针,在这种情况下,您需要使用new运算符:@H_403_3@
Node* func() { Node* pn = new Node(10); return n; }
但是,当您执行此操作时,您将为func调用方提供销毁相关对象的责任.由于new和delete是对称操作,因此将它们放在代码中的对称位置被认为是更好的形式,例如像这样:@H_403_3@
void cnuf(Node* p) { delete p; }
一个更好的替代方案可能是使用std :: shared_ptr,它为您提供引用计数,如下所示:@H_403_3@
std::shared_ptr<Node> func() { return std::make_shared<Node>(10); }
使用此方法,调用者无需手动管理每个节点的生命周期.另一种方法是使用std :: unique_ptr,它只允许单个对象所有权.
>或者您可以按值返回节点,您可以在本地创建它,然后让函数返回机制在您返回时复制它:@H_403_3@
Node func() { Node n(10); return n; }
问题2@H_403_3@
您可以在Node类声明中声明这样的析构函数:@H_403_3@
class Node { ... ~Node(); }
然后,您可以像这样定义它:@H_403_3@
Node::~Node() { ... }
但是,实际上让列表管理其Node实例(下一个字段)之间的连接,并且只让Node类管理其成员数据的生命周期(数据字段)可能更好.@H_403_3@