簡體   English   中英

返回指針與將引用傳遞給對象以將答案存儲在C ++中

[英]Returning a pointer vs. passing a reference to an object to store the answer in C++

我對在這種特殊情況下使用指針還是引用有一個普遍的疑問。

假設我有一個函數,它將執行一些計算並將該值存儲在對象中,以供調用者以后使用。 我可以通過使用指針或引用來實現。

雖然,我更喜歡使用引用,因為我嘗試盡可能地避免使用指針,一種方法相對於另一種方法是否有優點/缺點。

使用指針的代碼如下:

Node*& computeNode() {  
  // Do some computation before creating a node object.  
  Node* newNode = new Node;  
  newNode->member1 = xyz;  
  newNode->member2 = abc;  
  // and so on ...  
  return newNode;  
}

使用引用的代碼可以執行以下操作:

void computeNode(Node& newNode) {  
   // Do some computation before assigning values to the node object.  
   newNode.member1 = xyz;  
   newNode.member2 = abc;  
   // and so on.  
}

我可以看到的差異如下:

  1. 使用指針方法時,newNode對象將在堆上分配。 因此,除非我對其調用delete,否則它不會被刪除。 但是,在引用方法中,是否在堆/堆棧上分配newNode取決於調用者創建newNode對象的操作。

  2. 每當我們使用引用時,傳遞給函數的參數數量至少增加1。這很好,只有我發現將返回對象也傳遞給函數調用有點反常理,除非我在函數中命名函數這種方式對於API用戶而言顯而易見。

  3. 通過使用引用,我可以模擬多個對象的返回。 在指針方法中,我認為我必須將所有對象包裝在另一個結構(如pair類)中,然后將其返回。 這增加了開銷。

但是,我不知道通常一個人是否比另一個人更可取。 並且如果C ++中有任何函數命名約定,使開發人員知道他應該將返回對象也作為參數傳遞。

您可以嘗試返回auto_ptr或shared_ptr。 這樣可以消除刪除問題。

第二種方法可能更可取,因為在您忘記delete返回的指針的情況下,不會發生內存泄漏。

通常,以這樣一種方式進行編碼是一種好習慣,即分配堆內存的每個函數或對象也都會釋放該內存。 您的第一個示例違反了這種做法,這使函數調用者有責任重新分配內存。 這使內存泄漏的可能性更大,因為現在每次調用該函數時,都有另一個機會忘記刪除返回的指針。

在對象的大小不那么大的情況下,您可能還需要考慮按值返回對象(這將返回對象的副本)。 即使這需要創建一個副本,但如果對象不是很大,也不會影響性能。 (這種方法在將來會隨着C ++ 0x move語義變得更具吸引力。)

我認為您的第一個選擇應該是按值返回(或者讓構造函數計算成員?):

Node computeNode()
{
    Node n;
    n.x = abc;
    n.y = xyz;
    return n;
}

這看起來效率低下,但是很有可能使用NRVO消除了復制。

如果仍然需要動態分配Node,則應按值返回指針(指針的副本):

Node* computeNode();

否則,您將返回對局部變量(指針)的引用。

我更喜歡使用第二種方法發送回信息(如您所說,無需使用額外的結構即可進行多次“返回”),並且通常返回錯誤或成功代碼

另外,我將純輸入參數設置為const &以區分輸入變量和輸出變量。

您可以通過使用const引用按值返回並在某些情況下避免復制:

    Node computeNode() {
// Do some computation before creating a node object.
Node newNode;
newNode.member1 = xyz;
newNode.member2 = abc;
return newNode;
}

const Node &n = computeNode();

臨時對象在computeNode中的生存期已擴展到引用n的范圍

如果這些替代方案確實是給定的,則不清楚為什么您根本需要引用/指針。 您也可以按值返回:

Node computeNode() {
    // Do some computation before creating a node object.
    Node newNode;
    newNode.member1 = xyz;
    newNode.member2 = abc;
    return newNode;
}

盡管有許多人認為,但這實際上並不是很低效,因為編譯器可以(並且將!)淘汰大多數不必要的副本

從語義上講,這是您想要的解決方案,除非節點也存儲在其他位置並且您需要保留引用身份。

暫無
暫無

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

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