我应该返回引用堆对象还是返回值

Should I return reference to heap object or return value?

本文关键字:返回值 对象 返回 引用 我应该      更新时间:2023-10-16

我具有这两个简单的功能。我认为func1是一个很好的解决方案,因为您通过参考传递对象。我的教科书给了func2作为最佳解决方案的答案。这仅仅是因为您没有对heapstr进行交易?如果我在main中声明heapstr然后将其传递给函数,以便之后我可以将其删除?

#include <iostream>
using namespace std;

string& func1(const string &str) {
    string* heapstr=new string();
    for (int i = 0; i < str.size(); ++i) {
        *heapstr += str[i];
    }
    return *heapstr;
}
string func2(const string &str) {
    string heapstr;
    for (int i = 0; i < str.size(); ++i) {
        heapstr += str[i];
    }
    return heapstr;
}
int main() {
    cout << func1("aaa") << endl;
    cout << func2("aaa") << endl;
}

我应该返回引用堆对象还是返回值?

按值返回。

有很多原因原因,但是没有一个与性能真正相关的原因,因为编译器足够优化事物,即使不是,大多数程序都是I/O结合,即您的时间等待来自文件或网络插座的数据吞噬您的所有性能,而不是CPU操作本身所花费的时间。

参见Herb Sutter和Bjarne Stroustrup的" C 核心指南",在"按值返回容器(依靠移动或复制效率)"部分,请参见:

原因

简化代码并消除了对明确内存管理的需求。

至于您的两个功能...

我的教科书给了func2作为最佳解决方案的答案。这仅仅是因为您没有划分heapstr

内存泄漏是问题之一。但要点简单的是,按值返回更简单且容易发生。这全都是正确性,而不是速度。如果您可以返回int,您不会返回int*,您可以吗?

如果我在main中声明heapstr,然后将其传递给该函数,以便我可以将其删除?

您会在代码中引入许多可能性,以使内存泄漏,崩溃和未定义的行为。它将变得更长,更难写,更难阅读,更难维护,更难进行调试,并且在代码审查中更难证明是合理的。作为回报,您将一无所获。

教科书是正确的。(震惊。)

func1在与func2不同的各个方面都是错误的。它在不考虑如何删除该对象的情况下分配一个对象。然后,它返回对新对象的引用,隐藏可能已使用以删除它的指针。没有效率提高,实际上func1可能会慢一些。无论如何,背诵我:"避免早期优化。"

自从标准模板库的出现以来,许多卫星前几乎从来都不是最好的新运营商。我上次使用新运营商的是Ca。2003年,我将指针包裹在我们现在称为unique_ptr的等效方面。在使用新运营商之前,请阅读有关智能指针和raii的全部了解。

由于这是教科书示例,因此您应该考虑其上下文,以确定它想要确切显示的内容(其目标是将内存使用量最小化或使用安全的编程模式?!)。但是两个提示

  1. 当您使用new运算符分配内存时,您必须使用delete将其分配给它。该代码在func1上具有heapstr的内存泄漏。
  2. 在更现实的项目中,在方法之间共享对象是不安全的。它的管理(即当前对此进行了修改或负责在不需要的对象时将其分配给分配的人)变得困难。

ps:我没有C 17,但它也优化了以下内容。有关更多详细信息,请阅读@bopersson评论。

ps:堆栈分配更快,但是在您的示例中,您在func2返回时具有复制操作。在您的示例中,@Jive Dadson表示,由于编译器的优化没有差异,但在通常的情况下,假设以下代码

#include <iostream>
#include <string>
using namespace std;

string& func1(const string &str) {
    string* heapstr = new string();
    cout << "func1 " << heapstr << endl;
    for (int i = 0; i < str.size(); ++i) {
        *heapstr += str[i];
    }
    return *heapstr;
}
string func2(const string &str) {
    string heapstr;
    for (int i = 0; i < str.size(); ++i) {
        heapstr += str[i];
    }
    cout << &heapstr << endl;
    return heapstr;
}
int main() {
    string a = func1("aaa");
    string b = func2("aaa");
    cout << "main " << a << endl;
}

ps :(正如@Jive Dadson所说,您的示例没有区别,但在我的示例中),如果我们将性能定义为运行时间,也许是func1。另外,如果我们将性能定义为内存使用情况,则FUNC1。如果我们将性能定义为良好的编程模式,则func2。完全更喜欢func2。