7. 指针与引用
7.1. 不同点
1. 指针是一个对象,有存储的 值 和 地址 ,存储的数据类型是数据的地址;非常量指针可以被重新赋值,指向另一个对象。引用是对象的别名,必须初始化并总是指向(代表)最初绑定的那个对象,对对象及其引用进行取地址操作得到的结果相同。
1#include <iostream>
2using namespace std;
3
4int main(int argc, char ** argv)
5{
6 int k = 1;
7 int* pk = &k;
8 int& rk = k;
9
10 cout << "&k:" << &k << endl; // 0029FC44
11 cout << "k:" << k << endl; // 1
12
13 cout << "&pk:" << &pk << endl; // 0029FC68
14 cout << "pk:" << pk << endl; // 0029FC44 (pk = &k)
15 cout << "*pk" << *pk << endl; // 1
16
17 cout << "&rk:" << &rk << endl; // 0029FC44 (&rk = &k)
18 cout << "rk:" << rk << endl; // 1
19
20 return 0;
21}
2. 指针可以有多级,但是引用只能是一级(不存在 引用的引用 )。
3. 有 null pointer
,没有 null reference
,故使用前无需检查是非为空。
1void rValue(const int &x)
2{
3 cout << x << endl;
4}
5
6void pValue(const int* p)
7{
8 if(p) cout << *p << endl;
9}
一个例子:
1string s1("nancy");
2string s2("candy");
3string& rs = s1;
4string* ps = &s2;
5rs = s2; // rs仍指向s1,但是s1值变为"candy"。
6ps = &s2; // ps指向s2,s1无变化
7.2. 函数返回对象
考虑一个有理数的类,内含一个函数用来计算两个有理数的乘积。
1class Rational
2{
3friend
4const Rational operator*(const Rational& lhs, const Rational& rhs);
5// const Rational& operator*(const Rational& lhs, const Rational& rhs);
6
7public:
8 Rational(int _n = 0, int _d = 0): n(_n), d(_d){}
9private:
10 int n, d;
11};
12
13inline const Rational operator*(const Rational& lhs, const Rational& rhs)
14{
15 return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
16}
17// 这样做需要承担返回值的构造成本和析构成本
18// 但行为是正确的
绝对不要返回指向一个 local stack 对象的 pointer 或 reference。 局部变量会在函数返回后被销毁,因此被返回的引用就成为了“无所指”的引用,程序会进入未知状态。
1const Rational& operator*(const Rational& lhs, const Rational& rhs) 2{ 3 Rational result(lhs.n * rhs.n, lhs.d * rhs.d); // result 是 local 对象 4 return result; 5}
绝对不要返回指向一个 heap-allocated 对象(new)的 reference。 虽然不存在局部变量的被动销毁问题,但是面临其它局面:被函数返回的引用只是作为一个临时变量出现,而没有被赋给一个实际的变量,那么无法获取该引用背后的指针,则该引用所指向的空间(由new分配)就无法释放,造成 memory leak。
1const Rational& operator*(const Rational& lhs, const Rational& rhs) 2{ 3 Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d); // result 是 heap-allocated 对象 4 return *result; 5} 6 7int main() 8{ 9 Rational w, x, y, z; 10 w = x * y * z; // 这里使用了两次 new 11 return 0; 12} 13// 主函数结束时,已经执行了4 + 2次构造函数,4 次析构函数
绝对不要返回指向一个 local static 对象的 pointer 或 reference,因为有可能同时需要多个这样的对象。
7.3. 参考资料
《Effective C++》条款 21。
C++ 把引用作为返回值
在函数内new一个对象,如果作为引用返回,是不是就可以不用delete了?