这个问题特别与C ++ 98有关,但如果您愿意,可以随意提及任何有用的信息。
如果您知道答案并希望跳过剩下的部分,那么简短的&甜蜜的是:
int **w;
int volatile* *x = w; // error
int volatile*const*y = w; // OK
int const *const*z = w; // OK
为什么在const
声明中volatile
的{{1}}权利必须y
?如果x
的声明被允许,有人可能会做出什么样的恶事?
在标准的 4.4.4 部分中,它说:
转换可以在多级指针中的第一个级别添加cv-qualifiers ,但需遵守以下规则:
两种指针类型T1&如果存在类型T并且整数 n >,则T2 类似 0这样:
- T1是CV10 ptr至CV11 ptr至... CV1N T
- T2是CV20 ptr至CV21 ptr至... CV2N T
...每个CVij是const,volatile,const volatile或什么都不是。 cv限定符的
元组在指针类型中的第一个之后,例如指针类型T1中的CV11,CV12,...,CV1N,称为 cv-qualification signature 指针类型。类型T1的表达式可以转换为T2 iff ,满足以下条件:
- 指针类型类似
每个 j 的- > 0,如果const在CV1j中,则const在CV2j中,类似于volatile。
- 如果CV1j和CV2j不同,那么const在每个CV2k中 0< k< Ĵ
醇>
...之后,它继续举例说明**
到const**
。上面的强调是我的,斜体来自文档。
将其写入代码:
int CV13* CV12* CV11* CV10 b1;
int CV23* CV22* CV21* CV20 b2 = b1;
我对某些细节有点模糊......所以这里有一些问题或可能有缺陷的观察结果:
1)它说at levels other than the first
;这里没有详细说明,但CV20
可以是任何有效的CV限定符。
2)底部的第3条规则表示如果T2在级别const
添加volatile
或j
,则级别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
}
可以把邪恶放在那里?
答案 0 :(得分:2)
(注意:“这个问题特别与C ++ 98有关”,但是标准的所有版本的状态都是相同的,过去和现在(以及未来我也会打赌),因为它基本上是关于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
是{{ 1}})。
编辑:对于const
,问题可能不如使用volatile
那么明显,但允许转换会让您无声地错误地访问(读取或写入) volatile T,好像它不是volatile(通过指向 non -volatile T的指针):
const
但是通过添加“第一级”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;
是{{ 1}})。