我有这两个简单的功能。我认为#define MBGL_DEFINE_ENUM(T, values...)
是一个很好的解决方案,因为你通过引用传递了一个对象。我的教科书给出了func1
作为最佳解决方案的答案。这只是因为你没有解除分配func2
吗?如果我在main中声明heapstr
然后将其传递给函数,那么我之后能够删除它会怎么样?
heapstr
答案 0 :(得分:6)
我应该返回对堆对象的引用还是返回值?
按价值返回。
有很多原因,但没有一个与性能有关,因为编译器在优化方面已经足够好了,即使它不是,大多数程序都是I / O绑定的,即等待来自文件或网络套接字的数据的时间会耗尽所有性能,而不是CPU操作本身花费的时间。
例如参见" C ++核心指南"作者:Herb Sutter和Bjarne Stroustrup,他们在"Return containers by value (relying on move or copy elision for efficiency)"部分说:
原因
简化代码并消除显式内存管理的需要。
至于你的两个职能......
我的教科书给出
func2
作为最佳解决方案的答案。这只是因为你没有解除分配heapstr
吗?
内存泄漏是其中一个问题。但重点是,按值返回更简单,更不容易出错。这完全是关于正确性,而不是速度。如果您只能返回int*
,则不会返回int
,是吗?
如果我在
heapstr
中声明了main
然后将其传递给该函数,那么我之后能够删除它会怎么样?
您会在代码中引入很多内存泄漏,崩溃和未定义行为的可能性。它会变得更长,更难写,更难阅读,更难维护,更难调试,更难以在代码审查中证明其合理性。作为回报,你绝对不会获得任何收获。
答案 1 :(得分:2)
教科书是正确的。 (令人震惊。)
Func1在与func2不同的各个方面都有问题。它从堆中分配一个对象,而不考虑该对象的删除方式。然后它返回对新对象的引用,隐藏可能已经用于删除它的指针。没有效率增益,事实上Func1可能有点慢。在任何情况下,请背诵我:"避免早期优化。"
自标准模板库出现以来,许多月前,使用operator new几乎绝不是最佳选择。我最后一次使用operator new是ca. 2003年,我将指针包装在我们现在所知的unique_ptr中。在使用operator new之前,请阅读所有关于智能指针和RAII的所有知识。
答案 2 :(得分:1)
由于这是教科书示例,您应该考虑它的上下文以及它想要准确显示的内容(其目标是在您或使用安全编程模式时最小化内存使用量?!)。但有两个暗示
new
运算符分配内存时,必须使用delete
取消分配。该代码在heapstr
处有func1
的内存泄漏。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是更优选的。