为什么在C++中返回指向堆上变量的指针而不是变量本身

hea*_*ble 2 c++ heap stack pointers

所以我来自Java,现在正在学习C++,

我理解指针是如何工作的,堆栈和堆内存是什么,我已经google了很多但我似乎无法理解为什么我们不会只返回对象本身而不是指向堆上创建的对象的指针,如这个例子:

(我理解为什么我们必须在堆上分配对象而不是在第一个示例中的堆栈上.)

class Thingy;

Thingy* foo() 
{
  Thingy *pointerToHeap = new Thingy();
  return pointerToHeap;
}
Run Code Online (Sandbox Code Playgroud)

所以来自Java我会这样做:

class Thingy;

Thingy foo()
{
  Thingy a;
  return a;
}
Run Code Online (Sandbox Code Playgroud)

因为我几乎总是得到堆上的对象比堆栈中的对象长寿的原因,我不明白为什么我们会像第一个例子一样写一个函数,如果我的函数也能正常工作的话.

Ded*_*tor 6

你的两个例子不等同:

在Java示例中,您忘记了实际创建对象.
更正代码:

class Thingy;

Thingy foo() {
    Thingy a = new Thingy();
    return a;
}
Run Code Online (Sandbox Code Playgroud)

Java指针和C++指针的语法不同,因为Java不允许堆栈分配,只允许堆分配,也不允许分配非类型类型.这意味着不需要区分单级指针,多级指针和非指针变量,因为它们都是单级指针.

它们之间还有一个额外的语义差异:
虽然C++ 确实支持垃圾收集,但它非常罕见,而在Java中它是强制性的.

因此,在C++中,有两个更好的选择:

  1. 如果复制或移动便宜,则返回按值返回:

    class Thingy;
    Thingy foo() {
        Thingy t; // Thingy t(); would declare a function instead.
        return t; // The copy/move will probably be elided due to NRVO
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用a返回std::unique_ptr,明确表示所有权转移并使其异常安全:

    #include <memory>
    class Thingy;
    std::unique_ptr<Thingy> foo() {
        unique_ptr<Thingy> p = new Thingy();
        return p;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    如果从您的版本更改,此选项还具有不破坏ABI的优势,几乎适用于所有平台.
    虽然它打破了API,但这很容易纠正.

    • 另一种方法是返回a std::shared_ptr,以允许使用make_shared:

      #include <memory>
      class Thingy;
      std::shared_ptr<Thingy> foo() {
          auto p = std::make_shared<Thingy>();
          return p;
      }
      
      Run Code Online (Sandbox Code Playgroud)

  • @Styxs我不确定你的课程是否可以复制/移动,费用是多少.另外,我不知道你是否还有其他理由返回指针.一般来说,尽量远离指针.如果你必须使用指针,远离拥有原始指针,因为有更适合的智能指针. (2认同)