【问题标题】:C++ Returning Reference to New ObjectC++ 返回对新对象的引用
【发布时间】:2013-10-16 02:47:51
【问题描述】:

我知道有类似的问题,但他们都没有对我的问题给出明确的答案......

就最佳实践而言,这两种方法都可以吗?或者我应该返回一个指针? 如果不是,应该如何更改它们以遵循最佳实践。

我想从函数返回对新对象的引用。我的实现如下:

MyClass& doSomething() {
   return *(new MyClass());
}

MyClass a = doSomething();

这可以吗,因为 MyClass 的新实例正在用 new 分配在堆上?

或者我应该让它保持不变(我不确定什么时候这样做)?

const MyClass& doSomething() {
    return *(new MyClass());
}

如果这两个都错了,我应该只返回一个指向新对象的指针吗?

谢谢。

【问题讨论】:

  • 不需要 const,第一个选项很好。此外,如果需要,您也可以返回一个指针。由你决定。
  • 但是引用不是由调用者分配的。它是在调用过程中实例化的。因此我认为如果您不使用 new 那么它将超出范围,因为它将位于堆栈而不是堆上。
  • @BrianCain 他绝对需要new,否则对象将在doSomething() 完成后立即销毁。
  • @SergeSeredenko,受伤了,对不起。

标签: c++ pointers reference


【解决方案1】:

虽然这不是完全无效,但这不是一个好主意。

MyClass& doSomething() {
   return *(new MyClass());
}

返回后,没有人拥有原始指针,所以没有人会delete它。*所以这是内存泄漏。

你几乎不应该写一个new,除非你有一个对应的delete——或者,更好的是,一个智能指针构造函数。


同时,您的原始代码中的这一行:

MyClass a = doSomething();

... 无论如何都会复制该值。假设这不是另一个必须修复的错误,为什么还要麻烦堆分配对象并返回对复制和泄漏的引用?只需按值返回对象:

MyClass doSomething() {
   return MyClass();
}

现在您不必担心删除任何内容,因为您从未在堆上创建任何内容。


最佳实践通常可以总结为四个字母 RAII:资源获取即初始化。 (推论,破坏就是释放。)如果你有一些不可能或昂贵的东西,可以通过价值传递,然后通过价值传递一些句柄。例如:

unique_ptr<MyClass> doSomething() {
    return unique_ptr<MyClass>(new myClass());
}

unique_ptr<MyClass> a = doSomething();

现在它只是一个被复制的指针。对象本身在doSomething 内创建,并在a 超出范围时删除(或者,如果将其传递给另一个变量,则每当 that 超出范围等)。

另一方面,如果 MyClass 只是少数易于复制的值**,则只需复制它。


* 删除它并非不可能;您始终可以将指针指向引用和delete。你不太可能这样做,而且看起来很尴尬。如果要传递指针,请传递指针。如果您不想传递指针,请将所有权包装在一个类中并按值传递该类。

** 我所说的“易于复制”是指很容易安全地复制它们,而且你确实这样做了。例如,原始指针或文件句柄只有几个字节,默认的复制构造函数会很乐意为您复制它们……但是最终您会得到对同一个堆对象或文件的多个引用,并且无法跟踪谁负责删除或关闭它。

【讨论】:

  • 后者是否假设没有 RVO?还是我错过了什么......(我经常这样做,如果是这样,那就太惊讶了)。
  • @WhozCraig:无论有没有 RVO,编译器都无法优化新创建的指针,因为您明确要求它。如果你按值而不是按引用返回,那么 RVO 可以优化出一个副本,整个事情基本上是免费的。
  • 我必须在函数外部创建类才能按值传递它,对吗?感谢内存泄漏信息,我认为发生了一些奇怪的事情,但我无法弄清楚它是什么。基本上我正在创建的是一种工厂方法。那么返回指针应该可以工作吗?
  • 我的意思是你最后的 sn-p 与后续句子有关,但我现在看到它是指 OP 的代码,而不是一个毯子 this-will-copy-anyway 所以只是-做-这。我同意,RVO 或移动构造的按价值完全是做到这一点的方法。我什至没有注意到他在a decl+initializer 上泄漏了内存。不错的答案,顺便说一句。 +1
  • @SergeSeredenko:我意识到在原始版本中有点难以理解。最新编辑后是否足够清晰?谢谢。
猜你喜欢
  • 2015-12-17
  • 2021-07-28
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-26
  • 2019-05-23
  • 1970-01-01
相关资源
最近更新 更多