编译器: clang 6.0.0-1ubuntu2
自作主张翻译了一下。三个名词对应的原文分别是 multilevel pointer、type qualifier 以及 type conversion。选择用三个名词并列作为标题,也实在是因为涉及的内容根本无法用简短的句子描述出来。
不妨用一个例子开头:
int** ppi {nullptr}; const int** ppi2 {ppi};
编译报 Error: cannot initialize a variable of type 'const int **' with an lvalue of type 'int **'
,意即 int**
到 const int**
的隐式转换非法。
作为 C++ 的常识,top-level qualifier 在赋值时会被忽略,而 low-level qualifier 只可增不可减,如下例:
const int c{0}; int n {c}; // const of c is ignored const int* cp {nullptr}; int* np {cp}; // error
然而事实上,上述规则仅仅适用于一级指针的情况。本文首例中,ppi2 类型的最底层被加上 const 限定,但依然无法接收来自 int**
类型对象的赋值。
为理解原因,下面把首例拓展成为具有破坏性的代码。
const int i {0}; int *pi {nullptr}; int **ppi {&pi}; const int** ppi2 {const_cast<const int**>(ppi)}; *ppi2 = &i; **ppi = 1; // or *pi = 1;
第四行使用 const_cast
绕过编译器的检查,于是便造成了悲剧:本来不能指向 i
的 pi
以及 ppi
,在经过底层为 const 但上一级类型无 const 限定的 ppi2
变量的绕过后,获得了 i
的地址。因而原本有 const
限定的 i
被改变了值。
通过这个例子可以感受到,在涉及多级指针(2 级及以上)的情况下,赋值时的隐式类型转换中, low-level qualifier 即使增加也有可能造成隐患。
因此,指针类型 T1 到 T2 的类型转换能够被允许的情况需满足:
- T1 与 T2 基类型一致且指针级数相同;
- 记相同的指针层级为 n,同时记基类型所在的级别为 n 级,指针变量本身所在的级别为 0 级,中间各级按顺序排列。那么,若 T1 的 k 级(k > 0)存在某 qualifier,T2 的 k 级也需要有相同的 quailifier;
- 对于所有的 j > 0,若 T2 的 j 级存在 T1 的 j 级所不存在的 qualifier,那么 T2 中所有的 k 级(0 < k < j)都要有 const 限定。
既然用词是 qualifier,因此不只包括 const,还包括 volatile。
为了便于理解,举以下几个例子:
T***
类型的指针不能转换为T*const*
,因为不满足条件 1;T*const**
不能转换为T**const*
,因为不满足条件 2;T*const*****
不能转换为T*const**volatile***
因为不满足条件 3;但可以转换为T*const**volatile*const*const volatile*
类型的指针。
事实上,对于此类行为,C++ 17 标准 § 7.5 有着更详细清楚的规定。希望有钱后能直接拜读原文。结尾将附上某版草稿链接以供参考。
参考: N4140 号草稿 (其中 § 4.4 对应 C++ 17 标准 § 7.5)
Leave a Reply