在指针类型之间进行转换的规则,其中cv-qualifiers是唯一的区别

时间:2013-07-04 00:25:09

标签: c++ const volatile const-correctness c++98

这个问题特别与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 ,满足以下条件:

     
      
  1. 指针类型类似
  2.   每个 j
  3. > 0,如果const在CV1j中,则const在CV2j中,类似于volatile。
  4.   
  5. 如果CV1j和CV2j不同,那么const在每个CV2k中 0< k< Ĵ
  6.   

...之后,它继续举例说明**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添加volatilej,则级别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
}

可以把邪恶放在那里?

1 个答案:

答案 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}})。