浅谈: C++中*&的含义
前言
太长懒得看就直接跳到最下面小结,不过我不保证你一下能看懂。
指针引用
int *& A;
该类型要从右往左读:变量 A ,是一个引用 & ;谁的引用呢?指针 * 的引用。
为什么有些函数形参要用 *& 而不直接用 * 呢?
假设有这么一个函数:
void fun(int *A)
你把指针传给它的过程中,编译器会隐式地拷贝所传指针的一个副本,来拿给 fun 用。
也就是说 fun 实际接收到的指针 A 是你所传指针的一个克隆体,它俩所储存的地址相同(回忆指针的本质)。
你也许be like "so what?"。好吧,如果你只进行类似A->value=1
这种操作,两种写法是没区别的,因为这种操作不涉及对指针自身的更改。
那么请看下面两个例子。
例子1
这个例子中,假设原指针的地址为0xFF。你单纯手贱,想把原指针的地址乱改一通:
void fun(int *A) {
A = 0x0;
print(A); // C++没有这种形式的输出函数,只是为了方便写的
}
打印出来确实是0x0,你还沾沾自喜呢。但再在main函数里打印一下,你发现行不通了:
int main() {
int *ptr = 0xFF;
fun(ptr); // 输出:0x0
print(ptr); // 输出:0xFF
...
}
为什么呢?因为 A 是 ptr 的一个拷贝而已,你修改 A 自身根本不影响 ptr。
例子2
这个例子中,你声明了一个链表头指针,你想将它交给一个函数帮你制造一个链表,然后直接使用:
void fun(Node *ptr) {
ptr = new Node;
ptr->str = "hello world";
...
// 一些创建链表的代码
}
int main() {
Node *head = nullptr;
fun(head);
// 创建完直接使用:
print(head->str);
}
你是不是以为会打印出来 "hello world" ?结果什么都没打印,还报错 "segmentation fault"。
还是一样,ptr 是 head 的拷贝,两者一开始的值都是nullptr(空)
但只有 ptr 在 fun 里创建了一个新节点并存储其地址
后面一通创建操作结束回到 main 后,head 还是那个 head ,依旧指向空。你对它进行访问操作,必定报错。
小结
这两个例子的共同点是,出现了对指针自身进行修改的操作:
- 例子1:直接修改了 A 自身的地址值
- 例子2:间接(其实也是直接,只不过你没意识到)修改了 ptr 自身的地址值(ptr一开始是nullptr,new操作后便获取了一个新节点的地址值)
它们均出问题的原因在于:
- 代码作者的意图是在另一个函数里进行对原指针自身进行修改的操作,并希望这些操作在原指针上生效
- 然而该作者没意识到自己对指针自身的任何修改都是在原指针的一个克隆体上完成的
这时指针引用的作用就来了。如果将函数签名写为:
void fun(int *& A)
那么将指针传给它时,并不会产生拷贝机制,因为引用代表原指针的“替身”或“影子”,而不是“克隆体”。也就是你对原指针的“替身”打一拳,原指针是会受到伤害的。
都讲到这里了你不会还不懂8?