C++:在函数中创建新对象并将其作为结果返回时,是否必须使用 new 运算符来创建对象?

标签 c++ constructor destructor

我有两个虚拟问题让我困惑了一段时间。我确实在网上进行了一些搜索并通读了很多 C++ 教程,但是我找不到具体的答案。

假设我们有一个名为 Node 的类,它是单向链表的构建 block 。

class Node
{
   int data;
   Node* next;
}

事实1:局部变量(非静态)将在相应函数退出时被销毁。

问题1:情况如何:

Node* func()
{ 
    Node n; 
    Node* ptr=&n; 
    return n;
}

节点n会不会被销毁?或者我们必须使用 new 运算符来创建节点并返回指向堆内存的指针。如果两种方法都有效,哪种方法更好?

问题2:如何为节点类编写析构函数? (我在 stackOverflow 上发现了一些类似的问题,但这些答案集中在链表的析构函数上。我已经知道了那部分。我想要的正是 Node 类的析构函数)。

------------------------------------编辑------ ------------------------------

感谢所有给我建议或指出我错误的人。我想我得到了答案。下面是我根据您的回答做的笔记,它确实消除了我的困惑。

  1. 从函数返回堆栈内存地址不是一个好习惯,因为它会导致未定义的行为。
  2. 返回堆内存是可以的,但我们必须注意对象的销毁。
  3. 另一种方法是返回一个对象,受益于复制构造函数。

最佳答案

问题一

Node* func() { Node n; Node* ptr=&n; return n;}

您的代码创建一个本地 Node 实例(在堆栈上),然后返回它的地址。当函数返回时,作为局部变量的 Node 实例被销毁。函数返回的地址现在指向一些具有未定义内容的内存,任何取消引用此指针的尝试都将导致未定义的行为。

为了创建节点,您实际上需要调用Node 构造函数。你想如何返回结果与你如何调用构造函数有关。

  • 您可以像您尝试的那样返回一个指针,在这种情况下您需要使用 new 运算符:

      Node* func() { 
        Node* n = new Node(10); 
        return n;
      }
    

    但是,当您这样做时,您就赋予了 func 调用者销毁相关对象的责任。由于 newdelete 是对称操作,因此将它们放在代码中的对称位置被认为是更好的形式,例如像这样:

      void cnuf(Node* p) { 
        delete p; 
      }
    

    一个更好的替代方案可能是使用 std::shared_ptr,它可以为您提供引用计数,如下所示:

      std::shared_ptr<Node> func() {
        return std::make_shared<Node>(10);
      }
    

    使用这种方法,调用者不需要手动管理每个节点的生命周期。另一种替代方法是使用 std::unique_ptr,它只允许单一对象所有权。

  • 或者你可以按值返回节点,在这种情况下你在本地创建它,然后让函数返回机制在你返回它时制作一个拷贝:

      Node func() { 
        Node n(10); 
        return n;
      }
    

问题二

您可以在 Node 类声明中像这样声明一个析构函数:

class Node {
  ...
  ~Node();
}

然后,你可以这样定义它:

Node::~Node() {
  ...
}

但是,实际上让列表管理其 Node 实例(next 字段)之间的连接可能更好,并且只让 Node 类管理其成员数据的生命周期(data 字段)

关于C++:在函数中创建新对象并将其作为结果返回时,是否必须使用 new 运算符来创建对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26294543/

相关文章:

c++ - 我是否必须明确地销毁对象才能

c++ - C++构造函数抛出异常时销毁对象的成员变量

c++ - 继承层次结构 : Constructor & Destructor execution sequence

c++ - 使用条件变量的生产者和消费者线程

c++ - 为什么当这些对象中的任何一个不超出范围时调用析构函数?

c# - 没有定义的构造函数

c++ - 对参数化构造函数的显式调用会引发错误

c++ - 将 vector 合并到现有 vector 中

c++ - 迭代器如何找到链表中的下一个地址

java - java中的非静态嵌套类