简体   繁体   English

在cv限定词是唯一区别的指针类型之间进行转换的规则

[英]Rules for converting between pointer types where cv-qualifiers are the only difference

This question specifically relates to C++98, but feel free to pitch in any useful info w/regard to newer standards if you like. 这个问题专门与C ++ 98有关,但是如果您愿意的话,可以随意提供任何有用的信息,无论是否有更新的标准。

In case you know the answer and want to skip the rest, the short & sweet of it is: 如果您知道答案并想跳过其余的内容,则简短而优美的是:

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

Why would const be necessary to the right of volatile in the declaration of y ? 为什么在声明y需要在volatile权利上使用const What possible evil could someone accomplish if the declaration for x were allowed? 如果允许使用x的声明,某人可能会完成什么邪恶的事情?

In section 4.4.4 of the standard it says: 在标准的第4.4.4节中,它表示:

A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules: 转换可以在除多级指针中的第一个之外的其他级别上添加cv限定词,但要遵守以下规则:

Two pointer types T1 & T2 are similar if there exists a type T and integer n > 0 such that: 如果存在类型T并且整数n > 0,则两个指针类型T1和T2 相似 ,从而:

  • T1 is CV10 ptr to CV11 ptr to ... CV1N T T1为CV10 ptr至CV11 ptr至... CV1N T
  • T2 is CV20 ptr to CV21 ptr to ... CV2N T T2是CV20 ptr到CV21 ptr到... CV2N T

... where each CVij is const, volatile, const volatile, or nothing. ...每个CVij是const,volatile,const volatile或什么都不是。 The n-tuple of cv-qualifiers after the first in a pointer type, eg, CV11, CV12, ..., CV1N in the pointer type T1, is called the cv-qualification signature of the pointer type. 指针类型中第一个的cv限定词(例如,指针类型T1中的CV11,CV12,...,CV1N) 之后的n个元组称为指针类型的cv限定符 An expression of type T1 can be converted to type T2 iff the following conditions are satisfied: 类型T1的表达式可被转换当且仅当满足以下条件键入T2:

  1. the pointer types are similar 指针类型相似
  2. for every j > 0, if const is in CV1j, then const is in CV2j, and similarly for volatile. 对于每个j > 0,如果const在CV1j中,则const在CV2j中,对于volatile同样。
  3. if the CV1j and CV2j are different, then const is in every CV2k for 0 < k < j 如果CV1j和CV2j不同,则const在每个CV2k中为0 <k <j

... after which it goes on to give an example for assigning a ** to a const** . ......在这之后接着举一个例子用于分配**const** The emphasis above is mine, italics are from the document. 以上是我的重点 ,斜体来自文档。

Putting this into code: 将其放入代码中:

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

I'm a little fuzzy on some of the details ... so here's some questions or potentially flawed observations: 我对某些细节有些模糊...所以这是一些问题或可能存在缺陷的观察结果:

1) It says at levels other than the first ; 1)它说的at levels other than the first this isn't elaborated on any further, but CV20 can be any valid CV qualifier. 对此不再CV20 ,但是CV20可以是任何有效的CV限定词。

2) The 3rd rule at the bottom says if T2 adds either const OR volatile at level j , then levels 1 ... j-1 must be const (or suffer the wrath). 2)底部的第三条规则说,如果T2在级别j处添加constvolatile ,则级别1 ... j-1必须为const(否则会发怒)。 In the following, the # of stars differs from the one at the top to emphasize what the 3rd rule says: 以下,星号与顶部的星号有所不同,以强调第三条规则的含义:

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

I understand why it's needed for z , but why with y ? 我了解为什么z需要它,但为什么要使用y Here's roughly what the example in 4.4.4 looks like, modified for the volatile case: 这大致是4.4.4中的示例,针对易失性情况进行了修改:

void f( int **x ) {
  int volatile**y = x; // not allowed
  // do some evil here
}

What evil could be put there? 什么邪恶可以放在那里?

(Note: "This question specifically relates to C++98" but the state of affairs is the same in all versions of the Standard, past and present (and future too I would bet), because it's essentially about const-correctness and preventing coders from opening a hole in the type system.) (注意:“此问题专门与C ++ 98有关”,但是在过去和现在的所有版本标准中,事务的状态都是相同的(我敢打赌,将来也是如此),因为它本质上是关于const正确性和防止编码器在类型系统中打个洞。)

As the Standard uses the general term " cv-qualifiers ", I find it easier to understand when reasoning only with " const " (no " volatile ") [but see further below for an example with volatile ] . 由于该标准使用通用术语“ cv-qualifiers ”,因此我发现仅使用“ const ”(不使用“ volatile ”)进行推理时会更容易理解[但是请参见下文中有关volatile的示例] The "C++ FAQ Lite" has a related entry : Why am I getting an error converting a Foo**Foo const** ? “ C ++ FAQ Lite”具有一个相关条目: 为什么在转换Foo**Foo const**出错?

Essentially, allowing the conversion would let you silently modify a const T (through a pointer to non -const T): 本质上,允许进行转换将使您无提示地修改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!

But by adding a "first-level" const , the conversion int const* const* pcpc = pp; 但是通过添加一个“第一级” const ,转换为int const* const* pcpc = pp; is valid because the compiler will prevent you doing *pcpc = &theAnswer; 之所以有效,是因为编译器会阻止您执行*pcpc = &theAnswer; afterwards (because *pcpc is const ). 之后(因为*pcpcconst )。


Edit: As for volatile , the problem is maybe less obvious than with const , but allowing the conversion would let you silently incorrectly access (read or write) a volatile T as if it were not volatile (through a pointer to non -volatile T): 编辑:对于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

But by adding a "first-level" const , the conversion int volatile* const* pcpv = pp; 但是通过添加一个“第一级” const ,转换int volatile* const* pcpv = pp; is valid because the compiler will prevent you doing *pcpv = &externTimer; 是有效的,因为编译器将阻止您执行*pcpv = &externTimer; afterwards (because *pcpv is const ). 之后(因为*pcpvconst )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM