c++中的引用与指针的区别
副标题#e#
★ 沟通点:
1. 都是地点的观念;
指针指向一块内存,它的内容是所指内存的地点;引用是某块内存的别名。
★ 区别:
1. 指针是一个实体,而引用仅是个体名;
2. 引用利用时无需解引用(*),指针需要解引用;
3. 引用只能在界说时被初始化一次,之后不行变;指针可变;
引用“从一而终” ^_^
4. 引用没有 const,指针有 const,const 的指针不行变;
5. 引用不能为空,指针可觉得空;
6. “sizeof 引用”获得的是所指向的变量(工具)的巨细,而“sizeof 指针”获得的是指针自己(所指向的变量或工具的地点)的巨细;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,可是当引用作为成员时,其占用空间与指针沟通(没找到尺度的划定)。
7. 指针和引用的自增(++)运算意义纷歧样;
★ 接洽
1. 引用在语言内部用指针实现(如何实现?)。
2. 对一般应用而言,把引用领略为指针,不会犯严重语义错误。引用是操纵受限了的指针(仅容许取内容操纵)。
引用是C++中的观念,初学者容易把引用和指针夹杂一起。一下措施中,n 是m 的一个引用(reference),m 是被引用物(referent)。
int m;
int &n = m;
n 相当于m 的别名(外号),对n 的任何操纵就是对m 的操纵。譬喻有人名叫王小毛,他的外号是“三毛”。说“三毛”怎么怎么的,其实就是对王小毛说三道四。所以n 既不是m 的拷贝,也不是指向m 的指针,其实n 就是m 它本身。
引用的一些法则如下:
(1)引用被建设的同时必需被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必需与正当的存储单位关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的干系(指针则可以随时改变所指的工具)。
以下示例措施中,k 被初始化为i 的引用。语句k = j 并不能将k 修改成为j 的引用,只是把k 的值改酿成为6.由于k 是i 的引用,所以i 的值也酿成了6.
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和i 的值都酿成了6;
上面的措施看起来象在玩文字游戏,没有浮现出引用的代价。引用的主要成果是通报函数的参数和返回值。C++语言中,函数的参数和返回值的通报方法有三种:值通报、指针通报和引用通报。
以下是“值通报”的示例措施。由于Func1 函数体内的x 是外部变量n 的一份拷贝,改变x 的值不会影响n, 所以n 的值仍然是0.
void Func1(int x)
{
x = x + 10;
}
int n = 0;
Func1(n);
cout << “n = ” << n << endl;// n = 0
#p#副标题#e#
以下是“指针通报”的示例措施。由于Func2 函数体内的x 是指向外部变量n 的指针,改变该指针的内容将导致n 的值改变,所以n 的值成为10.
void Func2(int *x)
{
(* x) = (* x) + 10;
}
⋯
int n = 0;
Func2(&n);
cout << “n = ” << n << endl; // n = 10
以下是“引用通报”的示例措施。由于Func3 函数体内的x 是外部变量n 的引用,x和n 是同一个对象,改变x 便是改变n,所以n 的值成为10.
void Func3(int &x)
{
x = x + 10;
}
⋯
int n = 0;
Func3(n);
cout << “n = ” << n << endl; // n = 10
比拟上述三个示例措施,会发明“引用通报”的性质象“指针通报”,而书写方法象“值通报”。实际上“引用”可以做的任何工作“指针”也都可以或许做,为什么还要“引用”
这对象?
谜底是“用适当的东西做恰如其分的事情”。
指针可以或许毫无约束地操纵内存中的如何对象,尽量指针成果强大,但长短常危险。
就象一把刀,它可以用来砍树、裁纸、修指甲、剃头等等,谁敢这样用?
假如简直只需要借用一下某个工具的“别名”,那么就用“引用”,而不要用“指针”,以免产生意外。好比说,或人需要一份证明,原来在文件上盖上公章的印子就行了,假如把取公章的钥匙交给他,那么他就得到了不应有的权利。
——————————
摘自「高质量c++编程」
指针与引用,在More Effective C++ 的条款一有具体报告,我给你转过来
条款一:指针与引用的区别
#p#分页标题#e#
指针与引用看上去完全差异(指针用操纵符‘*’和‘->’,引用利用操纵符‘。’),可是它们好像有沟通的成果。指针与引用都是让你间接引用其他工具。你如何抉择在什么时候利用指针,在什么时候利用引用呢?
首先,要认识到在任何环境下都不能用指向空值的引用。一个引用必需老是指向某些工具。因此假如你利用一个变量并让它指向一个工具,可是该变量在某些时候也大概不指向任何工具,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,假如变量必定指向一个工具,譬喻你的设计不答允变量为空,这时你就可以把变量声明为引用。
“可是,请等一下”,你猜疑地问,“这样的代码会发生什么样的效果?”
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"
ps = &s2; // ps 此刻指向 s2;
// s1 没有改变
总的来说,在以下环境下你应该利用指针,一是你思量到存在不指向任何工具的大概(在这种环境下,你可以或许配置指针为空),二是你需要可以或许在差异的时刻指向差异的工具(在这种环境下,你能改变指针的指向)。假如老是指向一个工具而且一旦指向一个工具后就不会改变指向,那么你应该利用引用。
尚有一种环境,就是当你重载某个操纵符时,你应该利用引用。最普通的例子是操纵符[].这个操纵符典范的用法是返回一个方针工具,其能被赋值。
vector<int> v(10); // 成立整形向量(vector),巨细为10;
// 向量是一个在尺度C库中的一个模板(见条款35)
v[5] = 10; // 这个被赋值的方针工具就是操纵符[]返回的值
假如操纵符[]返回一个指针,那么后一个语句就得这样写:
*v[5] = 10;
可是这样会使得v看上去象是一个向量指针。因此你会选择让操纵符返回一个引用。(这有一个有趣的破例,拜见条款30)
当你知道你必需指向一个工具而且不想改变其指向时,可能在重载操纵符并为防备不须要的语义误解时,你不该该利用指针。而在除此之外的其他环境下,则应利用指针假设你有
void func(int* p, int&r);
int a = 1;
int b = 1;
func(&a,b);
指针自己的值(地点值)是以pass by value举办的,你能改变地点值,但这并不会改变指针所指向的变量的值,
p = someotherpointer; //a is still 1
但能用指针来改变指针所指向的变量的值,
*p = 123131; // a now is 123131
但引用自己是以pass by reference举办的,改变其值即改变引用所对应的变量的值
r = 1231; // b now is 1231
尽大概利用引用,不得已时利用指针。
当你不需要“从头指向”时,引用一般优先于指针被选用。这凡是意味着引用用于类的公有接口时更有用。引用呈现的典范场所是工具的外貌,而指针用于工具内部。
#p#分页标题#e#
上述的破例环境是函数的参数或返回值需要一个“临界”的引用时。这时凡是最好返回/获取一个指针,并利用 NULL 指针来完成这个非凡的使命。(引用应该老是工具的别名,而不是被清除引用的 NULL 指针)。
留意:由于在挪用者的代码处,无法提供清晰的的引用语义,所以传统的 C 措施员有时并不喜欢引用。然而,当有了一些 C++ 履历后,你会很快认识到这是信息埋没的一种形式,它是有益的而不是有害的。就如同,措施员应该针对要办理的问题写代码,而不是呆板自己。