2008-09-22 135 views
225

給人一種功能時,原來的變量一起工作會是怎樣更好的做法:指針與參考

unsigned long x = 4; 

void func1(unsigned long& val) { 
    val = 5;    
} 
func1(x); 

或:

void func2(unsigned long* val) { 
    *val = 5; 
} 
func2(&x); 

督察:是否有任何理由要挑一個比另一個?

+1

引用當然是有價值的,但我來自C,指針無處不在。一個人必須先熟悉指針才能理解引用的價值。 – 2012-05-08 19:43:27

+0

這與函數式編程中的參照透明度等目標是否相符?如果你總是希望函數返回新的對象,並且永遠不會內部改變狀態,尤其是不傳遞給函數的變量。有沒有一種方法,這個概念仍然用於像C++這樣的語言中的指針和引用。 (請注意,我假設有人已經有了參照透明度的目標。我不想談論它是否是一個好目標。) – ely 2013-09-30 17:31:01

+0

喜歡參考。用戶指針,當你沒有選擇。 – Ferruccio 2014-07-05 13:14:21

回答

254

我的經驗法則是:

使用指針,如果你想要做指針運算與他們(例如遞增指針地址步驟通過陣列),或者如果你曾經有傳遞一個NULL指針。

否則使用參考。

+9

有關指針爲NULL的優點。如果你有一個指針參數,那麼你必須明確地檢查它不是NULL,或者搜索函數的所有用法,以確保它不是NULL。引用不需要這種努力。 – 2008-09-22 11:10:02

+25

解釋你的算術意思。一位新用戶可能不瞭解你想調整指針指向的內容。 – 2008-09-22 16:30:29

+6

Martin, 算術我的意思是你傳遞一個指向結構的指針,但知道它不是一個簡單的結構,而是一個數組。在這種情況下,您可以使用[]對其進行索引,或者使用++/- 對指針進行算術運算。 這就是區別。 – 2008-11-25 20:35:40

63

我真的認爲你會從建立以下函數調用編碼準則受益:

  1. 正如其他所有地方,永遠是const -correct。

    • 注意:這意味着,除其他事項外,只有出值(參見第3項),並通過值傳遞值(參見第4項)可以缺少const說明符。
  2. 如果值0/NULL是當前上下文中的有效輸入,則只能通過指針傳遞值。

    • 理由1:作爲呼叫者,你看,不管你在傳遞必須處於可用狀態

    • 理由2:由於,你知道,無論在來處於可用狀態。因此,不需要對該值進行NULL檢查或錯誤處理。

    • 理由3:理據1和2將是編譯器執行。如果可以的話,一定要在編譯時發現錯誤。

  3. 如果函數參數是一個out-value,那麼通過引用傳遞它。

    • 理由:我們不希望打破2項...
  4. 選擇了「以const引用傳遞」僅當值是POD「按值傳遞」(Plain old Datastructure)或者足夠小(以記憶方式)或以其他方式足夠便宜(按時間)複製。

    • 理由:避免不必要的副本。
    • 備註:足夠小足夠便宜不是絕對的可測量的。
1

路過常引用,除非有你想改變/保存的內容你傳遞。

這將是在大多數情況下,最有效的方法的原因。

確保您對每個不希望更改的參數使用const,因爲這不僅可以保護您在函數中執行某些愚蠢的操作,還可以向其他用戶顯示該函數對傳入的值的作用。這包括當你只想改變指向什麼的時候指向一個指針...

22

這最終會變成主觀的。迄今爲止的討論是有用的,但我認爲這沒有一個正確或決定性的答案。很多將取決於時尚的風格指引和您的需求。

雖然使用指針有一些不同的功能(無論是否爲NULL),但輸出參數的最大實際區別純粹是語法。例如,Google的C++風格指南(https://google.github.io/styleguide/cppguide.html#Reference_Arguments)僅規定輸出參數的指針,並且只允許爲常量的引用。理由之一是可讀性:具有價值語法的東西不應具有指針語義含義。我並不是在暗示這一定是對是錯,但我認爲這裏的一點是,這是一個風格問題,而不是正確性問題。

2

引用是一個隱式指針。基本上你可以改變參考點的值,但是你不能改變參考來指向別的東西。所以我的2美分是,如果你只想改變一個參數的值作爲參考傳遞它,但如果你需要改變參數指向一個不同的對象使用指針傳遞它。

6

如果您要修改變量的值,您應該傳遞一個指針。 儘管在技術上傳遞引用或指針是相同的,但在用例中傳遞指針更具可讀性,因爲它「通告」了該函數將更改該值的事實。

4

如果你有一個參數,你可能需要指出缺少一個值,通常的做法是將參數設置爲一個指針值並傳入NULL。

在大多數情況下(從安全角度看),更好的解決方案是使用boost::optional。這使您可以通過引用傳遞可選值,也可以作爲返回值。

// Sample method using optional as input parameter 
void PrintOptional(const boost::optional<std::string>& optional_str) 
{ 
    if (optional_str) 
    { 
     cout << *optional_str << std::endl; 
    } 
    else 
    { 
     cout << "(no string)" << std::endl; 
    } 
} 

// Sample method using optional as return value 
boost::optional<int> ReturnOptional(bool return_nothing) 
{ 
    if (return_nothing) 
    { 
     return boost::optional<int>(); 
    } 

    return boost::optional<int>(42); 
} 
2

考慮C#的out關鍵字。編譯器要求方法的調用者將out關鍵字應用於任何out參數,即使它知道它們是否已經存在。這是爲了提高可讀性。雖然對於現代IDE,我傾向於認爲這是語法(或語義)突出顯示的工作。

1

指針:

  • 可以分配nullptr(或NULL)。
  • 在呼叫站點,如果您的類型不是指針本身,您必須使用&, 明確指出您正在修改您的對象。
  • 指針可以反彈。

參考文獻:

  • 不能爲null。
  • 一旦綁定,不能更改。
  • 呼叫者不需要明確地使用&。這有時被認爲是 不好,因爲你必須去執行該函數,看看你的參數是否被修改了 。
4

指針與Vs. Refereces

參考比指針那麼強大:

1)一旦參考被創建,它不能被以後作出引用另一個對象;它不能被重新安裝。這通常是用指針完成的。

2)參考文獻不能爲NULL。指針通常被設置爲NULL來表示它們沒有指向任何有效的東西。

3)聲明時的參考必須初始化。沒有與指針

沒有這樣的限制。由於上述限制,在C++ 引用不能被用於實現像鏈表數據結構,樹等在Java中,引用不具備上述限制,並可用於實現所有數據結構。在Java中引用更強大是Java不需要指針的主要原因。

引用是更安全,更易於使用:

1)更安全:由於引用必須初始化,像野指針野外引用是不可能存在的。它仍然可能有不指更易於使用的有效位置

2)參考文獻:參考文獻不需要對其操作訪問值。它們可以像正常變量一樣使用。 '&'運營商只有在申報時才需要。另外,對象引用的成員可以使用點運算符('。')來訪問,與需要使用箭頭運算符( - >)來訪問成員的指針不同。

連同上述原因,沒有幾個地方像拷貝構造函數的參數,其中不能使用指針。在複製構造函數中必須使用參數傳遞參數。同樣引用必須用於重載一些運營商如++