[英]Rules for converting between pointer types where cv-qualifiers are the only difference
這個問題專門與C ++ 98有關,但是如果您願意的話,可以隨意提供任何有用的信息,無論是否有更新的標准。
如果您知道答案並想跳過其余的內容,則簡短而優美的是:
int **w;
int volatile* *x = w; // error
int volatile*const*y = w; // OK
int const *const*z = w; // OK
為什么在聲明y
需要在volatile
權利上使用const
? 如果允許使用x
的聲明,某人可能會完成什么邪惡的事情?
在標准的第4.4.4節中,它表示:
轉換可以在除多級指針中的第一個之外的其他級別上添加cv限定詞,但要遵守以下規則:
如果存在類型T並且整數n > 0,則兩個指針類型T1和T2 相似 ,從而:
- T1為CV10 ptr至CV11 ptr至... CV1N T
- T2是CV20 ptr到CV21 ptr到... CV2N T
...每個CVij是const,volatile,const volatile或什么都不是。 指針類型中第一個的cv限定詞(例如,指針類型T1中的CV11,CV12,...,CV1N) 之后的n個元組稱為指針類型的cv限定符 。 類型T1的表達式可被轉換當且僅當滿足以下條件鍵入T2:
- 指針類型相似
- 對於每個j > 0,如果const在CV1j中,則const在CV2j中,對於volatile同樣。
- 如果CV1j和CV2j不同,則const在每個CV2k中為0 <k <j
......在這之后接着舉一個例子用於分配**
到const**
。 以上是我的重點 ,斜體來自文檔。
將其放入代碼中:
int CV13* CV12* CV11* CV10 b1;
int CV23* CV22* CV21* CV20 b2 = b1;
我對某些細節有些模糊...所以這是一些問題或可能存在缺陷的觀察結果:
1)它說的at levels other than the first
; 對此不再CV20
,但是CV20
可以是任何有效的CV限定詞。
2)底部的第三條規則說,如果T2在級別j
處添加const
或volatile
,則級別1 ... j-1
必須為const(否則會發怒)。 以下,星號與頂部的星號有所不同,以強調第三條規則的含義:
int *****w;
int **volatile* * *x = w; // error
int **volatile*const*const*y = w; // OK
int **const *const*const*z = w; // OK
我了解為什么z
需要它,但為什么要使用y
? 這大致是4.4.4中的示例,針對易失性情況進行了修改:
void f( int **x ) {
int volatile**y = x; // not allowed
// do some evil here
}
什么邪惡可以放在那里?
(注意:“此問題專門與C ++ 98有關”,但是在過去和現在的所有版本標准中,事務的狀態都是相同的(我敢打賭,將來也是如此),因為它本質上是關於const正確性和防止編碼器在類型系統中打個洞。)
由於該標准使用通用術語“ cv-qualifiers ”,因此我發現僅使用“ const
”(不使用“ volatile
”)進行推理時會更容易理解[但是請參見下文中有關volatile
的示例] 。 “ C ++ FAQ Lite”具有一個相關條目: 為什么在轉換Foo**
→ Foo const**
出錯?
本質上,允許進行轉換將使您無提示地修改const T(通過指向非 -const T的指針):
int const theAnswer = 42;
int* p = 0; // int* p = &theAnswer; is not allowed of course...
int** pp = &p;
int const** ppc = pp; // <-- Error, but imagine this were allowed...
*ppc = &theAnswer; // &theAnswer is `int const*` and *ppc is `int const*` too,
// but it's also doing *pp = &theAnswer; i.e. p = &theAnswer;
*p = 999; // I.e. theAnswer = 999; => modifying a const int!
但是通過添加一個“第一級” const
,轉換為int const* const* pcpc = pp;
之所以有效,是因為編譯器會阻止您執行*pcpc = &theAnswer;
之后(因為*pcpc
是const
)。
編輯:對於volatile
,問題也許比用不太明顯的const
,但允許轉換會讓你默默不正確的訪問(讀取或寫入) 揮發性 T作為如果沒有揮發物(通過一個指向非 -volatile T) :
extern int volatile externTimer;
int* p = 0; // int* p = &externTimer; is not allowed...
int** pp = &p;
int volatile** ppv = pp; // <-- Error, but imagine this were allowed...
*ppv = &externTimer; // &externTimer is `int volatile*` and *ppv too,
// but it's also doing *pp = &externTimer; i.e. p = &externTimer;
int a1 = externTimer; // First read
int a2 = externTimer; // Second read, mandatory: the value may have changed externally
int b1 = *p; // First read
int b2 = *p; // Second read? may be optimized out! because *p is not volatile
但是通過添加一個“第一級” const
,轉換int volatile* const* pcpv = pp;
是有效的,因為編譯器將阻止您執行*pcpv = &externTimer;
之后(因為*pcpv
是const
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.