0

假设我有:

    class SomeObject {

    };

    SomeObject& f() {
        SomeObject *s = new SomeObject();
        return *s;
    }

    // Variant 1
    int main() {
        SomeObject& s = f();
        // Do something with s
    }

   // Variant 2
    int main() {
        SomeObject s = f();
        // Do something with s
    }

第一个变体和第二个变体之间有什么区别吗?任何情况下我都会使用另一种?

编辑:还有一个问题,这s两种情况都包含什么?

4

4 回答 4

2

首先,您永远不想返回对在函数中动态分配的对象的引用。这是等待发生的内存泄漏。

除此之外,它取决于对象的语义以及您在做什么。使用引用(变体 1)允许修改它所引用的对象,以便其他一些函数将看到修改后的值。声明一个值(变体 2)意味着您拥有自己的本地副本,并且任何修改等都将针对它,而不是针对函数返回中引用的对象。

通常,如果函数返回对非常量的引用,那是因为它希望修改该值;一个典型的例子是类似std::vector<>::operator[]的,其中的表达式如下:

v[i] = 42;

预计会修改向量中的元素。如果 不是这种情况,那么函数应该返回一个值,而不是引用(并且您几乎不应该使用这样的函数来初始化本地引用)。当然,这只有在您返回对其他地方可访问的东西的引用时才有意义;函数所属的类拥有的全局变量或(更可能的)数据。

于 2013-11-14T10:11:18.730 回答
1

在第一个变体中,您将引用直接附加到动态分配的对象。这是拥有动态内存的一种相当非正统的方式(指针更适合该目的),但它仍然让您有机会正确释放该对象。即在你的第一个结束时main你可以做

delete &s;

在第二个变体中,您丢失了引用,即丢失了指向该动态分配对象的唯一链接。该对象成为内存泄漏。

同样,通过引用拥有动态分配的对象并不是一个好习惯。为此目的,通常最好使用指针或智能指针。出于这个原因,您的两个变体都有缺陷,即使第一个是正式可赎回的。

于 2013-11-14T10:44:51.713 回答
0

变体 1 将复制对象的地址并且会很快

变体 2 将复制整个对象并且会很慢(正如在 Variant2 中已经指出的那样,您不能删除通过调用 new 创建的对象)

进行编辑:两个 f 都包含相同的对象

于 2013-11-14T10:03:08.927 回答
0

你问的两个选项都不是很好。在这种特殊情况下,您应该使用shared_ptror unique_ptr,或者auto_ptr如果您使用较旧的 C++ 编译器,并更改函数以使其返回指针,而不是引用。另一个不错的选择是按值返回对象,尤其是在对象小且构造成本低的情况下。

按值返回对象的修改:

SomeObject f() { return SomeObject(); }

SomeObject s(f());

简单、干净、安全——这里没有内存泄漏。

使用unique_ptr

SomeObject* f() { return new SomeObject(); }

unique_ptr<SomeObject> s(f());

unique_ptr使用 a or here的优点之一shared_ptr是您可以f在某些时候更改您的函数以返回派生自的类的对象,SomeObject并且您的任何客户端代码都不需要更改 - 只需确保基类 ( SomeObject) 具有虚拟构造函数。

为什么您考虑的选项不是很好:

变体 1:

SomeObject& s = f();

你打算如何摧毁这个物体?无论如何,您都需要对象的地址来调用它的析构函数,因此在某些时候您需要取消引用引用s( &s)的对象

变体 2。这里有泄漏,没有机会调用函数返回的对象的析构函数。

于 2013-11-14T10:12:10.367 回答