文档章节

C/C++何时使用引用和指针

清风伴月
 清风伴月
发布于 2017/04/05 13:22
字数 1570
阅读 2
收藏 0

指针与引用何时使用呢,首先我们看More Effective C++ 中的详细条款讲述:

条款一:指针与引用的区别

指针与引用看上去完全不同(指针用操作符‘*’和‘->’,引用使用操作符‘&’),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢?

首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。

“但是,请等一下”,你怀疑地问,“这样的代码会产生什么样的后果?”

    char *pc = 0;// 设置指针为空值

    char& rc = *pc;// 让引用指向空值

这是非常有害的,毫无疑问。结果将是不确定的(编译器能产生一些输出,导致任何事情都有可能发生),应该躲开写出这样代码的人除非他们同意改正错误。如果你担心这样的代码会出现在你的软件里,那么你最好完全避免使用引用,要不然就去让更优秀的程序员去做。我们以后将忽略一个引用指向空值的可能性。

因为引用肯定会指向一个对象,在C里,引用应被初始化。

    string& rs;// 错误,引用必须被初始化

    string s("xyzzy");

    string& rs = s;// 正确,rs指向s

指针没有这样的限制。

    string *ps;// 未初始化的指针

// 合法但危险

不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。

void printDouble(const double& rd) {

    cout << rd; // 不需要测试rd,它肯定指向一个double值

} //相反,指针则应该总是被测试,防止其为空:

void printDouble(const double *pd) {

    if (pd)

        { // 检查是否为NULL cout << *pd; }

}

指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。

string s1("Nancy");

string s2("Clancy");

string &rs = s1; // rs 引用 s1

string *ps = &s1; // ps 指向 s1

rs = s2; // rs 仍旧引用s1,但是 s1的值现在是"Clancy",s1被更改,但是s2没有改变

ps = &s2; // ps 现在指向 s2;指针只是换换指向而已,并没有对内存单元中的值进行操作 ,s1 没有改变

总的来说,在以下情况下你应该使用指针,一是你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空),二是你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向)。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么你应该使用引用。

还有一种情况,就是当你重载某个操作符时,你应该使用引用。最普通的例子是操作符[].这个操作符典型的用法是返回一个目标对象,其能被赋值。

vector<int> v(10); // 建立整形向量(vector),大小为10

v[5] = 10; // 这个被赋值的目标对象就是操作符[]返回的值 ,如果操作符[]返回一个指针,那么后一个语句就得这样写:

*v[5] = 10; //此时只是为了说明问题而写的,编译器不一定能通过,有语义误解 ,但是这样会使得v看上去象是一个向量指针。因此你会选择让操作符返回一个引用。

当你知道你必须指向一个对象并且不想改变其指向时,或者在重载操作符并为防止不必要的语义误解时,你不应该使用指针。而在除此之外的其他情况下,则应使用指针假设你有

void func(int* p, int&r);

int a = 1;

int b = 1;

func(&a,b); //指针本身的值(地址值)是以值传递进行的,你能改变地址值,但这并不会改变指针所指向的变量的值,

p = someotherpointer;//a is still 1 ,但能用指针来改变指针所指向的变量的值,

*p = 123131; // a now is 123131 ,但引用本身是以引用传递进行的,改变其值即改变引用所对应的变量的值

r = 1231;// b now is 1231 ,尽可能使用引用,不得已时使用指针。

当你不需要“重新指向”时,引用一般优先于指针被选用。这通常意味着引用用于类的公有接口时更有用。引用出现的典型场合是对象的表面,而指针用于对象内部

上述的例外情况是函数的参数或返回值需要一个“临界”的引用时。这时通常最好返回/获取一个指针,并使用 NULL 指针来完成这个特殊的使命。(引用应该总是对象的别名,而不是被解除引用的NULL 指针)。

注意:由于在调用者的代码处,无法提供清晰的的引用语义,所以传统的 C 程序员有时并不喜欢引用。然而,当有了一些 C++ 经验后,你会很快认识到这是信息隐藏的一种形式,它是有益的而不是有害的。就如同,程序员应该针对要解决的问题写代码,而不是机器本身。

通过以上分析,本人认为:能使用引用的地方都能使用指针,反过来不行

© 著作权归作者所有

清风伴月
粉丝 1
博文 129
码字总数 255659
作品 0
海淀
程序员
私信 提问
C++ 备忘录 ( 持续更新中... )

Tip 1: #include包含头文件的问题 新的编译器格式: #include <iostream>using namespace std; 旧的编译器格式: #include <iostream.h> 注:旧的编译器格式中,包含头文件后,不添加 “usi...

谷鹏
2011/04/12
0
1
这一天,我用 Rust 重写了已有 19 年历史的 C++ 库!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdnnews/article/details/84948881 从版本 56 开始,Firefox 浏览器支持一种新的字符编码转换库,叫做 enco...

CSDN资讯
2018/12/10
0
0
C# vs C++之二:GC vs RAII

C# vs C++之二:GC vs RAII 资源管理 C中资源管理极为繁琐易错,大多复杂C系统都面临内存泄露、悬挂指针等问题 一方面由底层语言特点决定;另一方面也由于C语言特性相对较少,严重依赖程序员...

ddatsh
2011/06/28
1K
6
C++ Primer 学习笔记(第三章:字符串、向量和数组)

C++ Primer 学习笔记(第三章:字符串、向量和数组) [TOC] 3.1 命名空间的声明 声明语句可以一行放多条。 位于头文件的代码,一般来说不应该使用声明。因为其内容会拷贝到每个使用该头文件的...

ShawnLue
2015/08/20
0
0
从 C++ 到 Objective-C 的快速指南

简介 当我开始为iOS写代码的时候,我意识到,作为一个C++开发者,我必须花费更多的时间来弄清楚Objective-C中怪异的东西。这就是一个帮助C++专家的快速指南,能够使他们快速的掌握Apple的iOS...

oschina
2014/05/10
10.7K
30

没有更多内容

加载失败,请刷新页面

加载更多

代码持续自动发布

需求: 自动更新私人gitbook项目代码 如果代码没更新,不做务必要的构建操作 思路 定时任务加shell脚本,无论更新没更新都执行git pull。 优点:能满足需求 资源浪费,代码仓库不更新也执行p...

阿dai学长
11分钟前
0
0
sparkstreaming原理

Spark Streaming是Spark生态系统当中一个重要的框架,它建立在Spark Core之上,下面这幅图也可以看出Sparking Streaming在Spark生态系统中地位。 Spark Streaming是Spark Core的扩展应用,它...

七旬少女
30分钟前
0
0
springmvc集成cas,并解决前后端分离情况

1.最近项目需要集成已经存在的cas系统。 但是目前已集成的系统都是jsp。而我们项目是前后端分离开发(伪),没有分开部署。 2.cas原理就不介绍了 网上例子很多。基本都是使用302重定向实现的...

起名字什么的太麻烦了
46分钟前
4
0
HDFS-原理

1. 写操作

叶枫啦啦
今天
3
0
聊聊elasticsearch的MembershipAction

序 本文主要研究一下elasticsearch的MembershipAction MembershipAction elasticsearch-6.7.1/server/src/main/java/org/elasticsearch/discovery/zen/MembershipAction.java public class M......

go4it
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部