[英]Why const Ref on non-const pointer is interpreted as const pointer?
[英]Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"
將指向非常量的指針轉換為指向常量的指針是合法的。
那么為什么將指向非 const的指針的指針轉換為指向 const的指針的指針是不合法的呢?
例如,為什么下面的代碼是非法的:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!
從標准:
const char c = 'c';
char* pc;
const char** pcc = &pc; // not allowed
*pcc = &c;
*pc = 'C'; // would allow to modify a const object
忽略您的代碼並回答您的問題的原則,請參閱 comp.lang.c 常見問題解答中的此條目:為什么我不能將 char ** 傳遞給需要 const char ** 的函數?
不能將
char **
值分配給const char **
指針的原因有些模糊。 鑒於const
限定符完全存在,編譯器希望幫助您遵守不修改const
值的承諾。 這就是為什么您可以將char *
分配給const char *
,而不是相反:將const
-ness“添加”到一個簡單的指針顯然是安全的,但將其刪除會很危險。 但是,假設您執行了以下更復雜的一系列作業:const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */
在第 3 行,我們將
char **
分配給const char **
。 (編譯器應該抱怨。)在第 4 行,我們將const char *
分配給const char *
; 這顯然是合法的。 在第 5 行,我們修改了char *
指向的內容——這應該是合法的。 但是,p1
最終指向c
,即const
。 這出現在第 4 行,因為*p2
實際上是p1
。 這是在第 3 行中設置的,這是一個被禁止的表單的分配,這正是第 3 行被禁止的原因。
由於您的問題被標記為 C++ 而不是 C,它甚至解釋了要使用的const
限定符:
(C++ 有更復雜的分配 const 限定指針的規則,這使您可以在不產生警告的情況下進行更多類型的分配,但仍然可以防止無意中嘗試修改 const 值。C++ 仍然不允許將
char **
分配給const char **
,但它會讓您擺脫將char **
分配給const char * const *
。)
就因為沒有人發布解決方案,這里:
char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!
( http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17為什么)
C++11 草案標准在第4.4
節的注釋中解釋了這一點,其中說:
[注意:如果程序可以將 T** 類型的指針分配給 const T** 類型的指針(即,如果允許下面的第 1 行),則程序可能會無意中修改 const 對象(因為它已完成)在第 2 行)。 例如,
int main() { const char c = 'c'; char* pc; const char** pcc = &pc; // #1: not allowed *pcc = &c; *pc = 'C'; // #2: modifies a const object }
——尾注]
一個有趣的相關問題是Given int **p1 和 const int **p2 is p1 == p2 wellformed? .
請注意, C++ FAQ對此也有解釋,但我更喜歡標准中的解釋。
與注釋一致的文本如下:
轉換可以在多級指針的第一個以外的級別添加 cv 限定符,遵循以下規則:56
如果存在類型 T 和整數 n > 0 使得兩個指針類型 T1 和 T2 相似:
T1 是 cv1,0 指向 cv1,1 的指針指向 · · · cv1,n−1 指向 cv1,n 的指針 T
和
T2 是 cv2,0 指向 cv2,1 的指針指向 · · · cv2,n−1 指向 cv2,n 的指針 T
其中每個 cvi,j 是 const、volatile、const volatile 或什么都沒有。 指針類型中第一個之后的 cv 限定符的 n 元組,例如,指針類型 T1 中的 cv1,1, cv1,2, · · · , cv1,n,稱為指針類型的 cv 限定簽名. 當且僅當滿足以下條件時,類型 T1 的表達式才能轉換為類型 T2:
- 指針類型相似。
- 對於每個 j > 0,如果 const 在 cv1,j 中,那么 const 在 cv2,j 中,對於 volatile 也是如此。
- 如果 cv1,j 和 cv2,j 不同,則 const 在每個 cv2,k 中,因為 0 < k < j。
這里有兩條規則需要注意:
T*
和U*
之間沒有隱式轉換。T*
為T const *
。 (“指向 T 的指針”可以轉換為“指向 const T 的指針”)。 在 C++ 中,如果T
也是指針,那么這個規則也可以應用於它(鏈接)。例如:
char**
表示:指向 char 指針的指針。
而const char**
意味着:指向 const char 指針的指針。
由於指向 char 的指針和指向 const char 的指針是不同的類型,僅在常量性方面不同,因此不允許進行強制轉換。 要強制轉換的正確類型應該是指向 char 的 const 指針。
因此,要保持 const 正確,您必須從最右邊的星號開始添加 const 關鍵字。
所以char**
可以轉換為char * const *
,也可以轉換為const char * const *
。
此鏈接僅適用於 C++。 在 C 中,這種鏈接不起作用,因此在該語言中,您不能正確地轉換多於一層的指針 const。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.