C++中指针及指针引用的const正确性初始化/绑定规则问询
C++中指针及指针引用的const正确性初始化/绑定规则问询
先梳理下背景:C++里指针有四种const变体,具体如下:
B * = 非const指针指向非const B const B * = 非const指针指向const B(等价于下面这种写法) B const * = 非const指针指向const B B * const = const指针指向非const B const B * const = const指针指向const B(等价于下面这种写法) B const * const = const指针指向const B
这里的“非const指针”指你可以修改指针本身(比如执行p = NULL),“非const B”则指你可以修改指针指向的B对象(比如执行*p = 0)。
核心问题
我现在想搞清楚具体规则,来判断以下两种情况是否合法:
- 用一种const变体的指针
q初始化另一种变体的指针p时,什么时候合法? - 用一种const变体的指针
q初始化指向指针的引用r时,什么时候合法?
注意:这个问题只关注const属性,假设所有指针都指向同一个非指针类型的基类B。
这里的“初始化”包含以下几种场景:
- 声明变量时直接用
q初始化:P p = q; - 将
q作为实际参数传递给形参类型为P的函数:void myfunc(P p) {} myfunc(q); - 从返回类型为
P/R的函数中返回q:P myfunc() { return q; }
之前我想当然地以为规则很简单:只要指针本身的const属性和指向对象的const属性,不出现“移除const”的情况(也就是p/r在q有const的地方都有const)就合法。但实际测试了16种指针初始化组合和16种引用初始化组合后,我发现情况复杂得多——不仅指针和引用的行为不对称,每种情况内部还有奇怪的不对称性。
所以我想知道:这些const场景的精确规则是什么?在C++标准里的哪里能找到这些规则?
指针初始化的16种组合(右侧为简化伪代码,实际为左值q)
编译报错的标注为// err:
/*p00*/ B * p = B * q; /*p01*/ B * const p = B * q; /*p02*/ B const * p = B * q; /*p03*/ B const * const p = B * q; /*p04*/ B * p = B * const q; /*p05*/ B * const p = B * const q; /*p06*/ B const * p = B * const q; /*p07*/ B const * const p = B * const q; /*p08*/ B * p = B const * q; // err /*p09*/ B * const p = B const * q; // err /*p10*/ B const * p = B const * q; /*p11*/ B const * const p = B const * q; /*p12*/ B * p = B const * const q; // err /*p13*/ B * const p = B const * const q; // err /*p14*/ B const * p = B const * const q; /*p15*/ B const * const p = B const * const q;
其中让我意外的结果包括p00到p07的情况——看起来我们可以随意添加或移除指针本身的const属性。
指针引用初始化的16种组合(右侧为简化伪代码,实际为左值q)
编译报错的标注为// err:
/*r00*/ B * &r = B * q; /*r01*/ B * const &r = B * q; /*r02*/ B const * &r = B * q; // err /*r03*/ B const * const &r = B * q; /*r04*/ B * &r = B * const q; // err /*r05*/ B * const &r = B * const q; /*r06*/ B const * &r = B * const q; // err /*r07*/ B const * const &r = B * const q; /*r08*/ B * &r = B const * q; // err /*r09*/ B * const &r = B const * q; // err /*r10*/ B const * &r = B const * q; /*r11*/ B const * const &r = B const * q; /*r12*/ B * &r = B const * const q; // err /*r13*/ B const * const &r = B const * const q; // err /*r14*/ B const * &r = B const * const q; // err /*r15*/ B const * const &r = B const * const q;
这里的合法/非法模式(尤其是r02无法给B添加const,但r07却可以的情况)让我非常困惑。
备注:内容来源于stack exchange,提问作者Louis Semprini
相关产品推荐
相关产品推荐

