最近看代码遇到个指针的const引用的问题,指针真的是让人又爱又恨呐,太微妙了。指针和引用的再深入,记录分享下
我是在这里遇到的,简化代码如下:
template <class T> void show1(const T & i) { // i = (T)0x555555; 编译报错 // *i = 1314; 编译通过,效果正常 cout << (void*)i << endl; } void show2(const int* & i) { cout << (void*)i << endl; } int nTemp = 2019; int * ptrInt = &nTemp; show1(ptrInt); //可以通过编译,而且我已验证确实是真正的const引用 show2(ptrInt); //不能通过编译。cannot bind non-const lvalue reference of type 'const int*&' to an rvalue of type 'const int*' /简单来说就是这么个情况:
int nTemp = 2019; int *ptrInt = &nTemp; const *ptrInt2 = &nTemp; const int* &refptrInt1 = ptrInt; //1.这种用法会报错。你思考过吗,你觉得呢? //下面是验证代码 const int* &refptrInt2 = ptrInt2; //2.这个引用是const的吗 // *refptrInt2 = 999; //error: assignment of read-only location '* refptrInt2' refptrInt2 = (int*)0x1234; int* const &refptrInt2 = ptrInt; //3.其实,这个才是ptrInt的真正const引用。 *refptrInt2 = 999; // refptrInt2 = (int*)0x1234; //error: assignment of read-only reference 'refptrInt2'谈谈我的理解吧! 问题的关键还是在于const限定符修饰指针类型数据的神奇之处。也就是const在*之前之后的差异。
像如下这种单个token的类型说明符(比如int)很好理解,
int a = 0; const int &crefa = a;(等同表示:int const &crefa = a;)crefa标识符为const int引用类型,不能修改其标识符对应存储的值。
而像对于指针这种需要两个token的类型说明符(int*)的情况,就有时让人绕不过弯了。
int *pa = &a;(int*)类型pa标识符对应的const引用应该是哪种呢?首先,其const引用,表示的效果应该也是其标识符对应存储的值不能修改。指针还不就是一个存储的值为地址的特殊变量。然后,了解了const在*前后的差异就该明白了。
int nage = 18; const int *pt = &nage; //a pointer to const int,不能修改指针存储的地址指向的变量的值。 解引用后内容是常量。 int* const pu = &nage; //a const pointer to int,不能修改指针存储的地址,即改变不了指向的位置了。指针变量内容是常量。其对应的const引用,应该这样表达:
int* const &crefpa = pa; //和验证代码里的是一致的,这才是真正的指针的const引用想表达的意思而不该是const int* &crefpa = pa; 其对应的该是const int* pa = &a;
而且,引用设计上还不就是指针,其实就是类似如下的伪装表示:
int a; int & refint = a; int * const pint = &a;其const就该是
int [const] &refint = a; int [const] * const pint = &a; //[const] int * const pint = &a; 同上当为单个token,int时,其和const交换不影响编译器语义,如果是双token,int*时,不影响才怪呢。
int* [const] &refint = a; int* [const] * const pint = &a; //[const] int* * const pint = &a; 还同上吗?顺便说下,我遇到的情况,更验证了我的说辞。 而且,模板函数实例化看来是做了特殊处理了。类型参数T,可不是简单的替换啊,是一个独立的部分了。 比如当T == int *时,const T & 和T const&,是完全一样的,不影响语义,都是int* const &可以放心用其表示const引用。
template < class T > void show1(const T & i) { // i = (T)0x555555; 编译报错 // *i = 1314; 编译通过,效果正常 cout << (void*)i << endl; }
