这个问题特别与 C++98 有关,但如果您愿意,请随意提供任何与更新标准有关的有用信息。
如果您知道答案并想跳过其余部分,那么简短而有趣的是:
int **w;
int volatile* *x = w; // error
int volatile*const*y = w; // OK
int const *const*z = w; // OK
为什么在 y
声明中,const
必须位于 volatile
的右侧?如果允许 x
的声明,某人可能会做出什么恶事?
在标准的 4.4.4 部分中,它说:
A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:
Two pointer types T1 & T2 are similar if there exists a type T and integer n > 0 such that:
- T1 is CV10 ptr to CV11 ptr to ... CV1N T
- T2 is CV20 ptr to CV21 ptr to ... CV2N T
... where each CVij is const, volatile, const volatile, or nothing. The n-tuple of cv-qualifiers after the first in a pointer type, e.g., CV11, CV12, ..., CV1N in the pointer type T1, is called the cv-qualification signature of the pointer type. An expression of type T1 can be converted to type T2 iff the following conditions are satisfied:
- the pointer types are similar
- for every j > 0, if const is in CV1j, then const is in CV2j, and similarly for volatile.
- if the CV1j and CV2j are different, then const is in every CV2k for 0 < k < j
...之后,它继续给出将 **
分配给 const**
的示例。上面的强调是我的,斜体来自文档。
将其放入代码中:
int CV13* CV12* CV11* CV10 b1;
int CV23* CV22* CV21* CV20 b2 = b1;
我对一些细节有点模糊......所以这里有一些问题或可能有缺陷的观察:
1) 上面写着除第一级以外的其他级别
;对此不再详细说明,但 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 中的示例大致如下,针对 volatile 情况进行了修改:
void f( int **x ) {
int volatile**y = x; // not allowed
// do some evil here
}
那里会放什么邪恶的东西?
最佳答案
(注意:“这个问题特别与 C++98 有关”,但在所有版本的标准中,过去和现在(我敢打赌 future 也是如此)的情况都是相同的,因为它本质上是关于 const-正确性并防止编码人员在类型系统中打开漏洞。)
由于标准使用通用术语“cv-qualifiers”,我发现仅使用“const
”进行推理时更容易理解(没有“volatile
") [但请参阅下面的 volatile
示例]。 “C++ FAQ Lite”有一个相关条目:Why am I getting an error converting a 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
那么明显,但允许转换会让你默默地错误地访问(读或写)一个 volatile T,就好像它非 volatile (通过指向非- 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
)。
关于c++ - 指针类型之间的转换规则,其中 cv 限定符是唯一的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17460149/