2

这个问题特别与 C++98 相关,但如果您愿意,可以随意提供任何关于更新标准的有用信息。

如果您知道答案并想跳过其余部分,那么简短而有趣的是:

int **w;
int volatile*     *x = w; // error
int volatile*const*y = w; // OK
int const   *const*z = w; // OK    

为什么要在声明中对const权?如果允许声明 for ,某人可能会做出什么邪恶的事情?volatileyx

在标准的第4.4.4节中它说:

转换可以在多级指针中第一个以外的级别添加 cv 限定符,但须遵守以下规则:

如果存在类型 T 和整数n > 0,则两个指针类型 T1 和 T2 是相似的,使得:

  • T1 是 CV10 点到 CV11 点到 ... CV1N T
  • T2 是 CV20 点到 CV21 点到 ... CV2N T

...其中每个 CVij 是 const、volatile、const volatile 或什么都没有。指针类型中第一个之后的cv 限定符的 n 元组,例如指针类型 T1 中的 CV11、CV12、...、CV1N,称为指针类型的cv 限定签名。如果满足以下条件,则T1 类型的表达式可以转换为 T2 类型

  1. 指针类型相似
  2. 对于每个j > 0,如果 const 在 CV1j 中,则 const 在 CV2j 中,对于 volatile 也是如此。
  3. 如果 CV1j 和 CV2j 不同,则 const 在每个 CV2k 中,因为0 < k < j

...然后继续给出一个将 a 分配给 a 的**示例const**。上面的重点是我的,斜体来自文档。

将其放入代码中:

 int CV13* CV12* CV11* CV10 b1;
 int CV23* CV22* CV21* CV20 b2 = b1;

我对一些细节有点模糊......所以这里有一些问题或可能有缺陷的观察:

1)它说at levels other than the first;这不再详细说明,但CV20可以是任何有效的 CV 限定词。

2)底部的第三条规则说,如果 T2在 level 处添加constOR ,则 levels必须是 const (或遭受愤怒)。在下文中,星号的数量与顶部的星号不同,以强调第三条规则所说的内容:volatilej1 ... j-1

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
}

那里可以放什么邪恶?

4

1 回答 1

3

(注意:“这个问题特别与 C++98 相关”,但在标准的所有版本中,过去和现在(以及我敢打赌的未来)的情况都是相同的,因为它本质上是关于 const 正确性和防止编码员免于在类型系统中打开一个洞。)

由于标准使用通用术语“ cv-qualifiersconst ”,我发现仅使用“ ”(没有“ 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!

但是通过添加 "first-level" const,转换int const* const* pcpc = pp;是有效的,因为编译器会阻止你*pcpc = &theAnswer;之后做(因为*pcpcis const)。


编辑:至于volatile,问题可能不如 with 明显const,但允许转换会让您无声地错误地访问(读取或写入)易失性T,就好像它不是易失性的一样(通过指向非易失性 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

但是通过添加 "first-level" const,转换int volatile* const* pcpv = pp;是有效的,因为编译器会阻止你*pcpv = &externTimer;之后做(因为*pcpvis const)。

于 2013-07-19T09:29:32.080 回答