簡體   English   中英

C ++ const關鍵字 - 大量使用?

[英]C++ const keyword - use liberally?

在以下C ++函數中:

void MyFunction(int age, House &purchased_house)
{
    ...
}


void MyFunction(const int age, House &purchased_house)
{
    ...
}

哪個更好?

在兩者中,'年齡'都是按價值傳遞的。 我想知道'const'關鍵字是否有必要:對我來說似乎是多余的,但也很有用(作為額外的指示,變量不會改變)。

有沒有人對上述哪個(如果有的話)更好有任何意見?

首先,它只是一個實現細節, 如果你把const放在那里,不要把它放在聲明集(標題)中。 只將它放在實現文件中:

// header
void MyFunction(int age, House &purchased_house);

// .cpp file
void MyFunction(const int age, House &purchased_house);
{
    ...
}

參數在定義中是否為const純粹是一個實現細節,不應該是接口的一部分。

我經常沒見過這種事,我也不這樣做。 使用參數const會比幫助更容易讓我感到困惑,因為我會立即模式匹配 - 將其失敗為“const int&age”:)這當然與在另一個級別使用const完全不同:

// const is a *good* thing here, and should not be removed,
// and it is part of the interface
void MyFunction(const string &name, House &purchased_house);
{
    ...
}

在這種情況下,const將影響函數是否可以更改調用者的參數。 應盡可能經常使用此意義的Const,因為它可以幫助確保程序正確性並改進代碼的自我記錄。

我建議閱讀Herb Sutter。 特殊的C ++ 有一章“Const-Correctness”。

“事實上,對於編譯器,無論是否在值參數前面包含此const,函數簽名都是相同的。”

這意味着這個簽名

void print(int number);

實際上與此相同:

void print(int const number);

因此,對於編譯器,如何聲明函數沒有區別。 並且你不能通過將const關鍵字放在pass by value參數前面來重載它。

進一步閱讀,Herb Sutter建議:

“避免在函數聲明中使用const值傳遞參數。如果不修改參數const,則仍然將參數const置於同一函數的定義中。”

他建議避免這種情況:

void print(int const number);

因為那個const令人困惑,冗長和多余。

但在定義中,您應該這樣做(如果您不更改參數):

void print(int const number)
{
   // I don't want to change the number accidentally here
   ...
}

所以,你會確定即使在1000行函數的主體之后你總是沒有觸及數字。 編譯器將禁止您將該數字作為非const引用傳遞給另一個函數。

恕我直言,這是過度使用。 當你說'const int age,...'時你實際上說的是“你甚至不能改變你職能中的本地副本”。 你所做的實際上是通過強迫他在他想要改變年齡/通過非const引用傳遞它時使用另一個本地副本來降低程序員代碼的可讀性。

任何程序員都應該熟悉傳遞引用和傳遞值之間的區別,就像任何程序員應該理解'const'一樣。

您不僅表明它不會改變,它將阻止您的代碼認為它可以並且它將在編譯時被捕獲。

請參閱Meyers和'Effective C ++',並使用const自由,特別是使用pass-by-reference語義。

在這種原子變量的情況下,效率無關緊要,但代碼清晰度仍然有益。

好吧,正如其他人已經說過的那樣,從C ++語言的角度來看,上面的const對函數簽名沒有影響,即無論const是否存在,函數類型都保持不變。 它在抽象C ++語言級別上唯一的影響是你不能在函數體內修改這個參數。

但是,在較低級別,給定足夠聰明的編譯器,應用於參數值的const修飾符可以具有一些優化優勢。 考慮具有相同參數集的兩個函數(為簡單起見)

int foo(const int a, const double b, const long c) {
   /* whatever */
}

void bar(const int a, const double b, const long c) {
   /* whatever */
}

讓我們說代碼中的某處,它們被稱為如下

foo(x, d, m);
bar(x, d, m);

通常,編譯器在調用函數之前使用參數准備堆棧幀。 在這種情況下,堆棧通常會准備兩次:每次調用一次。 但是聰明的編譯器可能會意識到,由於這些函數不會更改其本地參數值(使用const聲明),因此為第一次調用准備的參數集可以安全地重用於第二次調用。 因此,它只能准備一次堆棧。

這是一種相當罕見且模糊的優化,只有在調用時已知函數定義(相同的轉換單元或高級全局優化編譯器)時才能工作,但有時可能值得一提。

說它“毫無價值”或“沒有效果”是不正確的,盡管使用典型的編譯器可能就是這種情況。

值得一提的另一個考慮因素是性質不同。 那里有編碼標准,要求編碼人員不要改變初始參數值,如“不要將參數用作普通局部變量,參數值應在整個函數中保持不變”。 這有點意義,因為有時它可以更容易地確定函數最初給出的參數值(在調試器中,在函數體內)。 為了幫助實施此編碼標准,人們可能會在參數值上使用const說明符。 值得與否是一個不同的問題......

使用const一個好處是你不能在MyFunction中間意外地改變age的值(如果你忘了它沒有通過引用傳遞)。 一個“缺點”是你不能用像foo.process(++age);這樣的代碼回收age foo.process(++age);

你是對的,“const int age”的唯一目的是年齡不能改變。 然而,對於大多數程序員來說,這可能是非常混亂的。 因此,如果這些方法沒有在您的代碼中廣泛使用,我建議省略const。

第二種變體更好。 在第一個中你可以意外地改變變量年齡。

如果(並且僅當)您將在任何其他不會被修改的局部變量上使用它,您應該在參數上使用const

const int age_last_year = age - YEAR;

在可能的情況下標記局部變量const有時很方便,因為這意味着您可以查看聲明並知道該值,而無需考慮中間代碼。 您可以在將來輕松更改它(並確保您沒有破壞函數中的代碼,如果它現在代表稍微不同的變量,可能會更改變量的名稱,這是可更改的,而不是之前的不變事情)。

與此相反,它確實使代碼更加冗長,而在一個簡短的函數中,幾乎總是非常明顯的是哪些變量發生了變化,哪些變量沒有變化。

那么,要么:

void MyFunction(const int age, House &purchased_house)
{
    const int age_last_year = age - YEAR;
}

要么:

void MyFunction(int age, House &purchased_house)
{
    int age_last_year = age - YEAR;
}

這里有一些很棒的文章和一本書,我發現解釋使用const的優點:


我可以向你提出以下格言嗎?

如果可以限定的對象/變量是常量,那么應該是。 在最壞的情況下,它不會花費任何成本。 最好的情況是,您將在代碼中記錄對象/變量的角色,這將使編譯器有機會進一步優化代碼。

有些編譯器忽略了使用'const'來利用優化的潛力,這導致許多專家在使用時忽略了常量參數的使用。 這種做法要求更嚴格,但不會有害。 在最壞的情況下,你不會失去任何東西,但是你也沒有獲得任何東西,而且充其量,你從使用這種方法中獲勝。


對於那些似乎不了解const函數/方法的by參數的實用程序的人......這里有一個簡短的例子,解釋了原因:

的.cpp

void WriteSequence(int const *, const int);

int main()
{
    int Array[] = { 2, 3, 4, 10, 12 };
    WriteSequence(Array, 5);
}


#include <iostream>
using std::cout;
using std::endl;
void WriteSequence(int const *Array, const int MAX)
{
    for (int const * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

如果我在int MAX前面刪除了const並且我在這里寫了MAX + 1會怎么樣?

void WriteSequence(int Array[], int MAX)
{
    MAX += MAX;
    for (int * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

那你的程序會崩潰! 現在,為什么會有人寫“MAX + = MAX;” 也許人為錯誤,也許程序員當天感覺不舒服,或者程序員根本不知道如何編寫C / C ++代碼。 如果你有const,代碼甚至都沒有編譯!

安全的代碼是很好的代碼,當你擁有它時,不需要花費任何東西來添加“const”!


以下是針對一個非常相似的問題的不同帖子的答案:

“當參數按值傳遞時,const是沒有意義的,因為你不會修改調用者的對象。”

錯誤。

它是關於自我記錄您的代碼和您的假設。

如果你的代碼中有很多人正在處理它並且你的功能是非常重要的,那么你應該將“const”標記為任何內容以及你能做到的一切。 在編寫工業級代碼時,你應該總是假設你的同事是精神病患者試圖以任何方式找到你(特別是因為它通常是你自己的未來)。

此外,正如之前提到的那樣,它可能有助於編譯器稍微優化一些事情(雖然這是一個很長的鏡頭)。

這是鏈接: 答案

具有通過值const傳遞的原始類型幾乎毫無價值。 將const傳遞給函數通常可以作為與調用者的契約,即函數不會更改該值。 在這種情況下,因為int是按值傳遞的,所以函數不能進行任何在函數外部可見的更改。

另一方面,如果不對對象進行任何更改,則rreferences和非平凡對象類型應始終使用const。 從理論上講,這可能會帶來一些優化,但最重要的是我上面提到的合同。 缺點當然是,它可以使您的界面更大,並且改進現有系統(或使用不使用const的第三方API)是一件困難的事情。

暫無
暫無

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

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