我应该返回引用堆对象还是返回值
Should I return reference to heap object or return value?
我具有这两个简单的功能。我认为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的全部了解。
由于这是教科书示例,因此您应该考虑其上下文,以确定它想要确切显示的内容(其目标是将内存使用量最小化或使用安全的编程模式?!)。但是两个提示
- 当您使用
new
运算符分配内存时,您必须使用delete
将其分配给它。该代码在func1
上具有heapstr
的内存泄漏。 - 在更现实的项目中,在方法之间共享对象是不安全的。它的管理(即当前对此进行了修改或负责在不需要的对象时将其分配给分配的人)变得困难。
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。
- 为什么模板类中的对象不能返回值
- 从 lambda 返回的对象将丢失属性值
- 如何通过对象的类属性删除对象,并返回其对象值?
- 为什么按值返回的对象与方法中的对象具有相同的地址?
- 实例化对象并调用方法,使用单行语法在 C# 或 C++ 中返回值?
- 初始化对象时,可以丢弃新的返回值吗?
- 当设置对象等于另一个函数的返回值时,为什么要调用移动构造函数/分配
- 从右值对象返回成员
- 在没有返回值优化的情况下将两个对象加在一起时,将创建多少个临时对象
- 我应该返回引用堆对象还是返回值
- 转发通用可可对象的返回值
- C++如何在模板中推断可调用对象的类型(参数列表和返回值)
- 在对类对象的赋值进行链接时获取垃圾值,使用按值返回类对象的赋值运算符重载
- 通过值或通过引用返回类对象,这在这里会更快
- 自定义类对象的向量的std::find的返回值
- 为什么getDC返回同一对象的不同值
- 未分配返回未定义对象类型引用的 C++ 函数的返回值时会发生什么情况
- 返回本地对象右值引用,正确或错误
- 从 MapViewOfFile() 的返回值构造自己的对象
- 有没有办法使用 move 而不是复制语义将函数返回值(对象)包装在 Python 中