常量指针和指针常量 (译自《 C++ common knowledge 》(美))

来源:互联网 发布:淘宝上靠谱的手机店 编辑:程序博客网 时间:2024/05/17 04:58

在日常的谈话中,程序员有时会经常说“常量指针”,尽管他们想表达的意思是“指向常量的指针”。这种观点是不准确的,因为它们完全是两种截然不同的概念。

 

T *pt = new T; //ptr to T

const T *pct = pt; // ptr to const T

T *const cpt = pt; // const ptr to T

 

       你想让某个东西成为const类型的,那你就昨首先明确它是什么:是指针,还是被指向的对象?或者两个都有?在pct的声明中,指针不是const类型的,但它指向的对象是。也就是说,const修饰符修饰的是T 基类,而不是针对指针。在cpt的案例中,我们声明了一个坚贞不屈、永远不会改变的、指向一个非const 类型的指针,const 做指针 cpt 的小妾,而 T 基类想摸她一下都不可以!

       若深究包裹在指针和const 的语法问题,那就一定得给个小提醒:const 不是说离谁近,就是谁的,一切得朝 * 号看齐!尽管潘金莲天天和西门庆在床上“风起云涌”、“你死我活”,但从法律层面讲,她依然是咱大郎哥的媳妇儿!请看下面的这两例,它们是完全一样的:

      

       const T *p1 ; // ptr to const T

       T const *p2; // also ptr to const T

 

       众所周知,第一种形式是更传统、更常见的,不过,现在越来越多的C++ 专家建议“识时务”的还是用第二种,为啥子来?因为与第一种相比,第二种形式更不容易被误导,你可以试着倒过来念,即:(*p2(const) (T)——pointer to const T(用中文说,就是“指向常量类T的指针”)。当然,如果大家心里都明白它们的意思和性质,那么用哪种形式都一样的啦。要特别小心的是,别因为一个在 * 号前后而导致的性质截然不同的错误,请看:

 

    T const *p3;   // ptr to const

       T *const p4;  // const ptr to non-const

      

       看到没?结果多可怕呀,一个是指向常量类的指针,一个是常量指针翘起自己的小鸡鸡指向一个非常量类!

       当然,定义一个指向常量类的常量指针也是可以的。

 

       const T *const cpct1 = pt;   // everything is const

       T const *const cpct2 = pt;   // the same with the above

 

       要知道,相比用常量指针,引用就简单的多了:

 

       const T &rct = *pt;   // rather than const T *const (而不是const T *const )

       T &rt = *pt;        // rather than T *const (而不是T *const )

 

       我们能够将一个指向非常量的指针转变成一个指向常量的指针(we are able to convert a pointer to non-const into a pointer to const )。例如,我们可以用T基类的指针pt的值来初始化一个指针(指向常量T),粗略地说它合法,是因为这样干不会出啥乱子(we were able to initialize pct (of type const T *) with the value of pt (of type T *). The reason this is legal is that, speaking nontechnically, nothing bad can happen.)。设想一下当一个非常量对象的地址被拷贝给一个指向const 的指针时将会出现什么结果,就像下面这个图所示:

 

    Figure 3. A pointer to const may refer to a non-const object.

图片

(不好意思,原图片不能复制,所以我自己画了一个)

    指向const 的指针pct 是指着一个非const T,但是这种情形不会造成任何伤害。事实上,用 const 类型的指针或者引用来指非 const 对象的做法很普遍的:

void aFunc( const T *arg1, const T &arg2 );

//...
T *a = new T;
T b;
aFunc( a, b );

       当我们调用函数aFunc时,我们用a 初始化 arg1 ,用b 初始化 arg2。我们没有声明 a 或者 b const 指针;但甭管是不是,在函数被调用而工作时,a, b在函数 aFunc 里面会被像 const 类型一样对待。这个技巧很有用。

       那么相反的一种转换,哎,也就是把一个指向const 的指针转换成指向非 const 的指针,是非法的,后果将会很危险!(The reverse conversion, from pointer to const to pointer to non-const, is not legal because it would be dangerous

 

                                          

                                             图片

 

 

    本例中,pct可能实际上在指向一个被定义为 const 型的对象。设想一下,如果我们能够将一个指向 const 的指针转化为一个指向非 const 的指针,那么本例中的 pt 就可以以此改变 acT 的值呀!

const T acT;

pct = &acT;

pt = pct; // 谢天谢地,在此编译器会通知程序员出错喽!                         

*pt = aT; // 看到没?这个指向非 const 的指针 pt 竞企图让 aT 赋值给它,以此来实现改变 const 变量 acT !!

       C++标准告诉我们类似这种无耻的赋值将会出现不可知的结局;我们不精确地知道结果会发生什么,但肯定不会是什么好下场!当然,我们可以采用一个 cast 进行顺利的转换。

pt = const_cast<T *>(pct); // not an error, but inadvisable不算错,但不建
                          //  议这样干  
*pt = aT; // attempt to change const object!

       然而,此类赋值行为的结果依然是不可预见的,如果 pt 是指向 acT 那种 const 型变量。

原创粉丝点击