Eol
感谢光临
Eol's Blog
C++ 多级指针、类型限定符与类型转换
C++ 多级指针、类型限定符与类型转换

编译器: 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 绕过编译器的检查,于是便造成了悲剧:本来不能指向 ipi 以及 ppi,在经过底层为 const 但上一级类型无 const 限定的 ppi2 变量的绕过后,获得了 i 的地址。因而原本有 const 限定的 i 被改变了值。

通过这个例子可以感受到,在涉及多级指针(2 级及以上)的情况下,赋值时的隐式类型转换中, low-level qualifier 即使增加也有可能造成隐患。

因此,指针类型 T1 到 T2 的类型转换能够被允许的情况需满足:

  1. T1 与 T2 基类型一致且指针级数相同;
  2. 记相同的指针层级为 n,同时记基类型所在的级别为 n 级,指针变量本身所在的级别为 0 级,中间各级按顺序排列。那么,若 T1 的 k 级(k > 0)存在某 qualifier,T2 的 k 级也需要有相同的 quailifier;
  3. 对于所有的 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)

Eol

文章作者

发表评论

textsms
account_circle
email

Eol's Blog

C++ 多级指针、类型限定符与类型转换
编译器: clang 6.0.0-1ubuntu2 自作主张翻译了一下。三个名词对应的原文分别是 multilevel pointer、type qualifier 以及 type conversion。选择用三个名词并列作为标题,也实在是因…
扫描二维码继续阅读
2019-09-17