2009-11-12 68 views
24

我知道關於const正確性的問題很少,它聲明函數的聲明及其定義不需要同意值參數。這是因爲值參數的常量只在函數內部很重要。這很好:Const參數值的正確性

// header 
int func(int i); 

// cpp 
int func(const int i) { 
    return i; 
} 

這樣做真的是最佳做法嗎?因爲我從來沒有見過任何人這樣做。我已經看到了這個報價(不知道來源的)在其他地方這個已經討論:

"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."

"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."

第二段說,不要把常量的聲明。我認爲這是因爲作爲接口定義的一部分,值參數的常量是沒有意義的。這是一個實現細節。

根據這個建議,是否也推薦指針參數的指針值? (因爲你不能重新分配的參考這是在參考參數毫無意義。)

// header 
int func1(int* i); 
int func2(int* i); 

// cpp 
int func1(int* i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compiles without error 

    return *i; 
} 
int func2(int* const i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compile error 

    return *i; 
} 

總結:製作值參數是捕捉一些邏輯錯誤。這是最佳做法嗎?你是否把const放在頭文件的極端?它對const指針值有用嗎?爲什麼或者爲什麼不?

一些參考:

C++ const keyword - use liberally? Use of 'const' for function parameters

當常數值參數都是有用的例子:

bool are_ints_equal(const int i, const int j) { 
    if (i = j) { // without the consts this would compile without error 
     return true; 
    } else { 
     return false; 
    } 
    // return i = j; // I know it can be shortened 
} 
+0

它惹人「如果(i = j)的」錯誤在這種情況下,但沒有捕捉到所有這些錯誤,所以我不會爲這個特定的基本原理感到興奮(因爲你可以用變量來做同樣的錯誤)。即使沒有const,如果你告訴它你想要警告,你的編譯器也會警告你。 – nobar 2009-11-13 04:29:52

+0

'if(i = j)'讓人興奮的一點是要認識到常量值參數不僅僅是絨毛。邁克爾伯爾的例子甚至比這個更好。 – jmucchiello 2009-11-13 06:35:14

+2

在不更改函數參數的情況下,應該對它們進行約束,因爲A)它更安全,B)它是自記錄的,C)它更易於調試。另外,原型和頭文件應該標記爲const。如果只是在函數頭部完成,那很令人困惑。有關在函數中創建臨時變量的爭論是一種情況,您可能不需要聲明參數const。這是我的2便士。 – 2011-09-19 20:52:23

回答

7

我對此採取:

這不是一個壞主意,但問題是次要的,你的能量可能會在其他的事情可能會更好一些。

在你的問題,你所提供的,當它可能趕上一個錯誤一個很好的例子,但偶爾也最終會做這樣的事情:

void foo(const int count ...) 
{ 
    int temp = count; // can't modify count, so we need a copy of it 
    ++temp; 

    /* ... */ 
} 

的利弊是次要的兩種方式。

+3

+1表示這不是一個壞主意,並指出這個問題很小。但在你複製參數之前,我只需要移除const(除非你總是複製「count」,作爲不對參數進行操作的原則,而不僅僅是因爲const阻止你) – 2009-11-12 18:27:39

+8

通常當你像這樣修改變量,你正在改變語義。例如:void foo(const int index0based){const int index1based = index0based + 1;}您可以將其稱爲索引並對其進行更改,但對於5年後出現的維護程序員而言,這一點更爲明確。 – Bill 2009-11-12 18:48:11

+0

@票據,優點! – 2009-11-12 18:51:48

9

我在一個函數讀取很多次,創造價值的參數const是一件壞事,因爲它是不必要的。

但是,我發現它偶爾對我有幫助,作爲一個檢查,我的實現不會做我不打算的事情(就像你的問題結尾的例子)。

所以,雖然它可能不會增加調用者的價值,但它有時會爲我實施者增加一點價值,並且它不會帶走任何東西。所以我認爲沒有害處使用它。

例如,我可能正在實現一個C函數,它將一對指針指向一個緩衝區 - 一個指向開始的指針和一個指向結尾的指針。我將把數據放入緩衝區,但要確保不會超出最後。所以在函數裏面有一些代碼會在我添加數據時增加一個指針。使指針指向緩衝區末尾的const參數將確保我不編碼意外增加結束邊界指針的錯誤,而不是我真的應該增加的指針。

所以有這樣的簽名fillArray功能:

size_t fillArray(data_t* pStart, data_t* const pEnd); 

會阻止我意外增加pEnd當我真正的意思是遞增pStart。這不是一件大事,但我很確定每個在C中編程了一段時間的人都遇到過這樣的錯誤。

+0

非常好。我正在尋找一個const指針值的好例子。 – jmucchiello 2009-11-12 19:02:34

1

不幸的是,一些編譯器(我看着你,太陽CC!)聲明不正確的參數常量和那些沒有宣佈這樣區分,你可以得到有關未定義函數的錯誤。

-2

我喜歡的情況const正確性是這樣的:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

這讓我使用b而不必擔心修改它,但我沒有付出拷貝構造函數的成本。

+8

我們不是在談論參考參數。僅限數值參數。 – jmucchiello 2009-11-12 19:00:58

0

我認爲這取決於你的個人風格。

它不增加或減少客戶端可以傳遞給你的函數。本質上它就像一個編譯時斷言。如果它幫助你知道價值不會改變,那就去做吧,但我認爲別人沒有這麼做的重要原因。

一個原因,我可能不會做它該值參數的常量性是一個實現細節,你的客戶端不需要了解。如果您以後(故意)更改函數以確實更改該值,則需要更改函數的簽名,這將強制客戶重新編譯。

這類似於爲什麼有些人建議有沒有公共虛擬方法(功能虛擬岬是一個實現細節應該從客戶端被隱藏),但我不是在特定的陣營。

+2

重讀這個問題。頭文件沒有const,因爲正如你所說,調用者並不關心實現是否修改局部變量。這是一個嚴格的問題,在實施方面是否值得。 – jmucchiello 2009-11-12 19:06:43

0

如果存在const關鍵字;它意味着'我'(這是const類型)的值不能被修改。 如果「i」的值foo的函數編譯器內改變將引發錯誤:「

Can not modify const object

但改變‘* I’(即* I = 3;)意味着你不能改變的值‘我’,但由「我」

其實指向的地址的值,const的功能適用於不應該由功能改變大對象。

0

我們都必須解開別人的C++代碼時有發生。而這別人的C++代碼是一個完全混亂的定義:D。

因此,我經常要做的第一件事情就是解密它(本地&全局數據流),將const放在每個變量定義中,直到編譯器發出抱怨。這也意味着const限定值的參數,它確實有助於避免在函數中間被修改的變量,而我沒有注意到它...

所以,我真的很感激,當別人有常量到處(包括值參數):d