c++ - const function




const int*,const int*const和int const*之間有什麼區別? (9)

  1. 常量引用:

    對一個變量(這裡是int)的引用,它是常量。 我們主要將變量作為參考傳遞,因為引用的大小比實際值小,但是存在副作用,這是因為它就像是實際變量的別名。 我們可能通過完全訪問別名來意外更改主變量,所以我們使其不變以防止這種副作用。

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. 常量指針

    一旦一個常量指針指向一個變量,那麼它就不能指向任何其他變量。

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. 指向常量

    一個不能改變它指向的變量值的指針被稱為常量指針。

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. 常量指針

    指向常量的常量指針既不能改變它指向的地址,也不能改變保存在該地址的值。

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

我總是搞砸如何正確使用const int*const int * constint const * 。 是否有一套規則來定義你可以做什麼和不可以做什麼?

我想知道所有的做法和所有的要點,包括任務,傳遞給功能等。


一般規則是const關鍵字適用於立即之前的內容。 例外,起始const適用於後面的內容。

  • const int*int const*相同,意思是“指向常量int的指針”
  • const int* constint const* const相同,意思是“指向常量int的常量指針”

編輯:對於該做什麼和不該做什麼,如果這個答案還不夠,你能更準確地知道你想要什麼嗎?


向後讀取(由順時針/螺旋規則驅動):

  • int* - 指向int的指針
  • int const * - 指向const int的指針
  • int * const - const指向int的指針
  • int const * const - const int指針

現在第一個const可以在類型的任一側,如下所示:

  • const int * == int const *
  • const int * const == int const * const

如果你想變得非常瘋狂,你可以做這樣的事情:

  • int ** - 指向int **指針的指針
  • int ** const - 一個指向int的指針的const指針
  • int * const * - 指向指向int的常量指針的指針
  • int const ** - 指向const int指針的指針
  • int * const * const - 一個指向int * const * const的常量指針的const指針
  • ...

並確保我們清楚const的含義

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo是一個指向常量整數的變量指針。 這可以讓你改變你指向的內容,但不會改變你指向的價值。 大多數情況下,您可以看到C風格的字符串,其中有一個指向const char的指針。 您可以更改指向哪個字符串,但不能更改這些字符串的內容。 當字符串本身位於程序的數據段中時,這一點很重要,不應該改變。

bar是一個常數或固定指針,可指向可更改的值。 這就像沒有額外語法糖的參考。 由於這個事實,除非需要允許NULL指針,否則通常會使用T* const指針的引用。


在C ++中圍繞const正確性還有很多其他細節。 我想這裡的問題只是關於C,但我會給出一些相關的例子,因為標籤是C ++:

  • 您經常會將大量參數(如字符串)傳遞為TYPE const & ,以防止對像被修改或複制。 示例:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    TYPE & const是無意義的,因為引用總是const。

  • 您應該始終將不修改類的類方法標記為const ,否則您無法從TYPE const & reference調用該方法。 示例:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • 常見的情況是返回值和方法都應該是const。 示例:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    實際上,const方法不能返回內部類數據作為非const引用。

  • 因此,必須經常使用const重載創建一個const和一個非const方法。 例如,如果你定義T const& operator[] (unsigned i) const; ,那麼你可能還需要非const的版本:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik在C中沒有const函數,非成員函數本身在C ++中不是const,const方法可能有副作用,編譯器不能使用const函數來避免重複的函數調用。 事實上,即使是一個簡單的int const & reference也可以見證它引用的值在其他地方被改變。


幾乎每個人都指出:

const X* pX* const pconst X* const p之間的區別是什麼?

您必須從右向左讀取指針聲明。

  • const X* p意思是“p指向一個X是const”:X對像不能通過p來改變。

  • X* const p表示“p是一個非常量X的常量指針”:你不能改變指針p本身,但你可以通過p改變X對象。

  • const X* const p意思是“p是一個常量指針X的常量指針”:你不能改變指針p本身,也不能通過p改變X對象。


我想所有的東西都已經在這裡回答了,但我只想補充一點,你應該小心typedef s! 它們不只是文本替換。

例如:

typedef char *ASTRING;
const ASTRING astring;

astring的類型是char * const ,而不是const char * 。 這是我總是傾向於將const放在該類型右側的原因之一,並且從不在開始。


簡單使用'const'

最簡單的用法是聲明一個命名常量。 為此,我們聲明一個常量,就好像它是一個變量,但在它之前加上'const'。 一個人必須立即在構造函數中初始化它,因為當然,之後不能設置該值,因為它會改變它。 例如,

const int Constant1=96; 

將創建一個整數常量,無法想像地稱為'Constant1',其值為96。

這些常量對程序中使用的參數非常有用,但在程序編譯後無需更改。 它對於程序員來說優於C預處理器的'#define'命令,因為它可以被編譯器自己理解和使用,而不是在到達主編譯器之前被預處理器替換為程序文本,所以錯誤消息更有幫助。

它也適用於指針,但必須注意'const'的位置,以確定指針或指向的內容是常量還是兩者。 例如,

const int * Constant2 

聲明Constant2是變量指針,指向一個常量整數和

int const * Constant2

是一種可替代的語法,但是

int * const Constant3

聲明Constant3是一個指向變量整數的常量指針

int const * const Constant4

聲明Constant4是常量指針,指向一個常量整數。 基本上'const'適用於其左側的任何內容(除非在這種情況下它沒有任何內容適用於它的直接權利)。

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html : http://duramecho.com/ComputerInformation/WhyHowCppConst.html


這主要解決第二行:最佳實踐,作業,功能參數等。

一般實踐。 盡量讓所有的東西都可以。 或者換一種說法,先將所有東西都設為const ,然後刪除允許程序運行所必需的最小const集合。 這對於獲得常量正確性會有很大的幫助,並且有助於確保在人們嘗試分配不應該修改的內容時不會引入細微的錯誤。

避免像瘟疫一樣的const_cast <>。 有一個或兩個合法的用例,但它們很少。 如果你試圖改變一個const對象,那麼你會更好地找到誰能夠以第一步的方式聲明它是const ,並且與他們談論這件事情,以便就應該發生什麼達成共識。

這導致非常整齊地分配任務。 只有當它是非常量時才可以分配給某些東西。 如果你想分配一些常量,參見上文。 請記住,在聲明int const *foo;int * const bar; 不同的東西是const - 其他答案在這裡已經很好地解決了這個問題,所以我不會去討論它。

功能參數:

按值傳遞:例如void func(int param)您不會在呼叫站點以某種方式關心其他方法。 這個參數可以作為聲明函數為void func(int const param)用例,但對調用者沒有影響,只對函數本身有效,因為在函數期間傳遞的任何值都不能被該函數改變電話。

通過引用傳遞:例如void func(int &param)現在它確實有所作為。 正如剛剛聲明的func允許更改param ,任何呼叫站點都應該準備好處理後果。 將聲明更改為void func(int const &param)更改合約,並確保func現在不能更改param ,這意味著傳入的內容將返回。 正如其他人所指出的,這對於便宜地傳遞一個不想更改的大對象非常有用。 通過引用比按價值傳遞大對象便宜很多。

通過指針傳遞:例如void func(int *param)void func(int const *param)這兩個和它們的引用同義詞幾乎是同義詞,但要注意的是被調用函數現在需要檢查nullptr除非有其他契約保證確保func永遠不會收到paramnullptr

關於該主題的意見片。 在這樣的情況下證明正確性是非常困難的,這太容易犯錯了。 所以不要冒險,並且總是檢查nullptr指針參數。 你可以節省自己的痛苦和痛苦,並且很難找到長期的錯誤。 至於檢查的成本,它便宜得多,並且在編譯器內置的靜態分析可以管理它的情況下,優化器無論如何都會將其忽略掉。 打開MSVC的鏈接時間代碼生成,或WOPR(我認為)GCC,你會得到它的程序範圍,即使在跨越源代碼模塊邊界的函數調用。

在一天結束時,上述所有內容都使得一個非常可靠的例子總是喜歡引用指針。 它們全面更安全。


這很簡單,但棘手。 請注意,我們可以將const限定符與任何數據類型( intcharfloat等)進行交換。

我們來看下面的例子。

const int *p ==> *p是只讀的[ p是指向常量整數的指針]

int const *p ==> *p是只讀的[ p是指向常量整數的指針]

int *p const ==> 錯誤的語句。 編譯器引發語法錯誤。

int *const p ==> p是只讀的[ p是一個指向整數的常量指針]。 由於這裡的指針p是只讀的,所以聲明和定義應該在同一個地方。

const int *p const ==> 錯誤的語句。 編譯器引發語法錯誤。

const int const *p ==> *p是只讀的

const int *const p1 ==> *pp是只讀的[ p是指向常量整數的常量指針]。 由於這裡的指針p是只讀的,所以聲明和定義應該在同一個地方。

int const *p const ==> 錯誤的語句。 編譯器引發語法錯誤。

int const int *p ==> 錯誤的語句。 編譯器引發語法錯誤。

int const const *p ==> *p是只讀的,等價於int const *p

int const *const p ==> *pp是只讀的[ p是指向常量整數的常量指針]。 由於這裡的指針p是只讀的,所以聲明和定義應該在同一個地方。





const