繁体   English   中英

在C ++中按引用返回-引用分配与值分配

[英]Return by reference in C++ - Reference assignment vs value assignment

假设我有:

    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包含什么?

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

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

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

v[i] = 42;

预期会修改向量中的元素。 如果不是这种情况,则该函数应返回一个值,而不是引用(并且您几乎永远不应使用此类函数来初始化本地引用)。 当然,只有返回对其他位置可访问内容的引用,这才有意义。 函数所属的类所拥有的全局变量或(更可能是)数据。

在第一个变体中,您将引用直接附加到动态分配的对象。 这是拥有动态内存的一种非常不合常规的方法(指针将更适合于该目的),但是它仍然为您提供了适当地重新分配该对象的机会。 即在您的第一个main结束时,您可以执行

delete &s;

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

同样,通过引用拥有动态分配的对象并不是一个好习惯。 为此通常最好使用指针或智能指针。 因此,即使第一个变体可以正式兑换,您的两个变体也存在缺陷。

变体1将复制对象的地址,并且速度很快

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

编辑:两个f包含相同的Object

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

修改以按值返回对象:

SomeObject f() { return SomeObject(); }

SomeObject s(f());

简单,干净,安全-这里没有内存泄漏。

使用unique_ptr

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

unique_ptr<SomeObject> s(f());

在此处使用unique_ptrshared_ptr的优点之一是,您可以在某个时候更改函数f以返回派生自SomeObject的类的对象,并且无需更改任何客户端代码-只需确保基类( SomeObject )具有虚拟构造函数。

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

变体1:

SomeObject& s = f();

您将如何销毁物体? 无论如何,您都将需要该对象的地址来调用它的析构函数,因此有时需要取消引用s所指的对象( &s )。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM