6

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

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

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

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

MyClass a = doSomething();

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

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

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

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

谢谢。

4

1 回答 1

8

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

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

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

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


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

MyClass a = doSomething();

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

MyClass doSomething() {
   return MyClass();
}

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


最佳实践通常可以总结为四个字母 RAII:Resource Acquisition Is Initialization。(并且推论,破坏就是释放。)如果你有一些不可能或昂贵的东西,可以通过价值传递,然后通过价值传递一些句柄。例如:

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

unique_ptr<MyClass> a = doSomething();

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

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


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

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

于 2013-10-16T03:00:24.840 回答