您的位置:首页 > 其它

指针和引用

2018-02-02 21:17 92 查看

1、引用

引用必须初始化

引用就是给对象取一个别名。定义引用,程序把引用和它的初始值绑定在一起(绑定之后不可再绑定其他对象),而不是初始值拷贝引用,为了完成对应的绑定,引用必须初始化。引用类型必须和绑定对象类型严格匹配。

操作引用

引用赋值,就是把值赋给了与引用绑定的对象。获取引用值,实际上就是获取了与引用绑定对象的值。

引用必须指向某个固定对象,之后不可修改

首先引用并不是对象,所以不能定义引用的引用。引用也不可以指向空值,所以使用引用不需要测试其合法性因为必定指向某个对象。

int val = 4;
int &ref = val;//引用绑定,给val起个别名。
ref = 34;//写引用,实际写val。
int val1 = ref;//读引用,实际读取val。

char *pc = 0;
char &rc = *pc;//引用指向空值。结果未定义,大错特错了。

string &rs;//错误,未初始化。


2、指针

指针是变量,用于指向某个对象(存储某个对象的地址)。

1. 指针可以不初始化

  因为是变量,所以可以不初始化,因此在传递指针函数里面通常需要测试指针的合法性。

2. 指针指向内容可以改变

 这就是废话,变量内容肯定可以变化。

3、何时用引用,何时用指针?

1、指向一个对象并且不想改变其指向时或者在重载操作符并为防止不必要的语义误解时,应该使用引用。

vector<int> v(10);
int & operator[](size_type n)
{
return *(begin() + n);
};//返回对象的引用,可修改对象。
v[5] = 10;//这种操作合理,是因为返回的引用,可以直接修改。

//假如返回指针
*v[5] = 10;//这种操作容易引发误解,并且不好看。


2、其他一切情况,都应该使用指针。

   考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空)。能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向)。

  

4、尽量使用传引用,而不是传值

除非明确指定,函数的形参总是通过“实参的拷贝”来初始化,函数的调用者得到的也是函数返回值的拷贝。

传值

通过值来传递一个对象”的具体含义是由这个对象的类的拷贝构造函数定义的,这使得传值成为一种非常昂贵的操作,因为传值意味着创建对象,拷贝实参。通常对应着许多构造函数和析构函数的调用。

传引用

没有构造函数或析构函数被调用,因为没有新的对象被创建。传递引用和指针也可以解决切割问题。详解参见《C++ Primer》。最后要说的是,引用几乎都是编译器通过指针来实现的,所以通过引用传递对象实际上是传递指针。因此,如果是一个很小的对象例如int类型,传值实际上会比传引用更高效但是被调用函数需要修改实参数值,那么还是得传递引用或者指针。

5、被调用函数必须返回对象时不要试图返回其引用

引用只是一个名字,某个已经存在的对象的名字。无论何时看到一个引用的声明,就要立即问自己:它的另一个名字是什么呢?因为它必然还有另外一个什么名字。加入另一个对象不存在,那么就不要强制返回引用了,该返回对象就返回对象。

1、返回局部对象引用

inline const Rational& operator*(const Rational& lhs , const Rational& rhs)
{
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}


被调用函数的局部对象创建在栈上,函数退出对象就会销毁,那么再返回其引用是毫无意义且结果未定义。

2、返回堆中对象引用

inline const Rational& operator*(const Rational& lhs , const Rational& rhs)
{
Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}

Rational w, x, y, z;//用户代码,这里的骚操作产生必定内存泄漏
w = x * y * z;//这里new了两个对象,w使用完毕后,最后必定内存泄漏。


通过在堆中动态创建对象,然后返回引用是可行的,但是这通常对应着内存泄漏的问题,调用者不可能去释放你分配的内存。写一个返回废弃指针的函数无异于坐等内存泄漏的来临。

3、通过定义静态对象返回引用

bool operator==(const Rational& lhs , const Rational& rhs);
inline const Rational& operator*(const Rational& lhs , const Rational& rhs)
{
static Rational result; //将要作为引用返回的
return result;
}

//以下是程序员骚操作
Rational a, b, c, d;
if ((a * b) == (c * d)){
;
}else{
;
}
/*
if相当于以下操作。
并且static的result是operator*函数公有的;
if (operator==(operator*(a, b), operator*(c, d)))

operator*(a, b)和operator*(c, d)公用一个result,这里肯定返回都是真。所以必定出现无敌Bug。
*/


因为更加不可行,因为某些操作是不成立的。

4、返回对象

这时候返回对象才是正确的。

inline const Rational operator*(const Rational& lhs,
const Rational& rhs)
{
return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}


这样就不会出现前面各种Bug,所以你应该明白这里所说的东西。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: