在 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)表示您拥有自己的本地副本,并且任何修改等将是针对它,而不是对象在函数返回中引用。
通常,如果函数返回对非常量的引用,这是因为它期望修改值;一个典型的示例类似于std::vector<>::operator[]
,其中表达式如下:
v[i] = 42;
预期会修改向量中的元素。 如果这是不是这种情况,那么函数应该返回一个值,而不是一个引用(你几乎不应该使用这样的函数来初始化本地引用)。 当然,这只会使是否返回对可访问内容的引用别处;全局变量或(更有可能)数据由函数所属的类拥有。
在第一个变体中,您将引用直接附加到动态分配的对象。这是一种相当非正统的拥有动态内存的方式(指针更适合此目的),但它仍然让您有机会正确释放该对象。即在你的第一个main
结束时,你可以做
delete &s;
在第二个变体中,您将丢失引用,即丢失指向该动态分配对象的唯一链接。对象变为内存泄漏。
同样,通过引用拥有动态分配的对象对我来说不是一种好的做法。通常最好使用指针或智能指针来实现此目的。出于这个原因,您的两个变体都有缺陷,即使第一个变体在形式上是可兑换的。
变体 1 将复制对象的地址并且速度很快
变体 2将复制整个对象并且速度很慢(正如变体 2 中已经指出的那样,您无法删除通过调用 new 创建的对象)
对于编辑:两个 f 都包含相同的对象
您询问的两个选项都不是很好。在这种特殊情况下,您应该使用 shared_ptr
或 unique_ptr
,或者如果您使用较旧的C++编译器,则应使用 auto_ptr
,并更改函数以使其返回指针,而不是引用。另一个不错的选择是按值返回对象,特别是如果对象很小且构造成本低。
修改以按值返回对象:
SomeObject f() { return SomeObject(); }
SomeObject s(f());
简单,干净,安全 - 这里没有内存泄漏。
使用unique_ptr
:
SomeObject* f() { return new SomeObject(); }
unique_ptr<SomeObject> s(f());
在这里使用 unique_ptr
或 shared_ptr
的一个优点是,您可以在某个时候更改函数f
以返回从SomeObject
派生的类的对象,并且不需要更改任何客户端代码 - 只需确保基类 (SomeObject
) 具有虚拟构造函数即可。
为什么您考虑的选项不是很好:
变式 1:
SomeObject& s = f();
你打算如何摧毁这个物体?无论如何,您都需要对象的地址来调用其析构函数,因此在某些时候您需要取消引用s
引用的对象(&s
)
变式2.这里有一个泄漏,没有机会调用从函数返回的对象的析构函数。
- 标准库类型的赋值运算符的引用限定符
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 为什么我需要三个嵌套的大括号来调用赋值运算符,将const引用到二维数组
- 复制引用结构上的赋值
- 作为赋值(增加引用变量)C++的左操作数所需的左值
- 如果类在 C++ 中具有常量或引用类型的非静态数据成员,为什么编译器不提供默认赋值运算符?
- 返回 T 引用的 Const 函子禁止赋值
- 为什么在C++中,内建赋值返回的是非常量引用而不是常量引用
- 输入迭代器是否可以仅在赋值的右侧符号上取消引用?
- 为什么类的赋值运算符的返回类型通常是非常量(而不是常量)引用?
- 引用模板类型的赋值运算符需要非常量重载
- 为什么在取消引用的指向接口的指针上使用赋值运算符不是编译器错误
- 为什么 GCC 拒绝复制赋值操作中的常量引用
- 赋值不起作用,但带有取消引用运算符的地址起作用?
- 为引用元组赋值
- 如何为具有自引用指针的类实现复制构造函数/赋值运算符
- 为什么 Visual C++ 编译器允许临时赋值到左值引用
- 常量引用向量向量<向量<long>>赋值不编译
- 通过解引用NULL指针来赋值引用
- Shared_ptr赋值:引用计数顺序