You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:40:26