簡體   English   中英

我應該返回堆對象的引用還是返回值?

[英]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可能有點慢。 在任何情況下,請背誦我:“避免早期優化。”

自標准模板庫出現以來,許多月前,使用operator new幾乎都不是最佳選擇。 我最后一次使用operator new是ca. 2003年,我將指針包裝在我們現在所知的unique_ptr中。 在使用operator new之前,請閱讀所有有關智能指針和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是更優選的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM