最近看代码遇到个指针的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;
}