设为首页 加入收藏

TOP

C++ 中“空引用”与“空指针”的区别 (一)
2014-11-23 21:12:48 来源: 作者: 【 】 浏览:47
Tags:引用 指针 区别

网络上有很多讨论C++ 的“引用”与“指针“的区别的文章,谈到区别,其中有一条:“引用不能为空(NULL),引用必须与合法的存储单元关联,指针则可以是NULL)”,但在实际应用中,有时候为了保持一致性,我们会抛开这个规则,人为创造出一个“空引用”。

很多情况下,“空引用”确实可以工作,以致于“引用不能为空”的忠告,被嘲笑为形式主义,仅仅是标准制定者的耸人听闻。一个“空引用”的例子是:

[cpp]
int * a = NULL;
int & b = *a;

int * a = NULL;
int & b = *a;于是当访问b的时候,程序异常出现了:

[cpp]
void f(int & p)
{
p = 0;
}
f(b);

void f(int & p)
{
p = 0;
}
f(b);当然,可以增加点判断,修正这个问题:

[cpp]
void f(int & p)
{
if (&p) p = 0;
}

void f(int & p)
{
if (&p) p = 0;
}
怎么样,是不是有点别扭?但是如果换成成指针,你要输入的字符数是一模一样的:

[cpp]
void f(int * p)
{
if (p) *p = 0;
}

void f(int * p)
{
if (p) *p = 0;
} 于是,到底是使用“引用”还是“指针”,好像就是智者见智仁者见仁的事情了。

然而,然而。。。。。。

这真的一样吗?

我们来看看复杂一点的例子:

[cpp]
// test.cpp

#include

class A
{
int a;
};

class B
{
int b;
};

class C
: public A, public B
{
int c;
};

void fb(B & b)
{
std::cout << &b << std::endl;
}

void fb(B * b)
{
std::cout << b << std::endl;
}

int main(int argc, char* argv[])
{
C * c = NULL;

fb(c);

fb(*c);

return 0;
}

// test.cpp

#include

class A
{
int a;
};

class B
{
int b;
};

class C
: public A, public B
{
int c;
};

void fb(B & b)
{
std::cout << &b << std::endl;
}

void fb(B * b)
{
std::cout << b << std::endl;
}

int main(int argc, char* argv[])
{
C * c = NULL;

fb(c);

fb(*c);

return 0;
}
编译运行一下看看:

[plain]
$ ./test
0
0x4

$ ./test
0
0x4咦,怎么&b不是0,也就是不是“空引用”了,这时候,即使加上判断,if (&b),也无济于事了。

大家也许注意到了,上面是linux环境运行,那么windows环境呢:

[plain]
>test.exe
00000000
00000000

>test.exe
00000000
00000000这时候,“空引用”保持了他的“空”属性,仅在windows平台做C++的开发者,可以松口气了。

这是怎么回事呢,是你的眼睛欺骗了你?也许是,但是CPU不会欺骗我们,从汇编代码可以看出本质。下面是linux平台编译的代码:

[plain]
Dump of assembler code for function main:
0x0804870a <+0>: push %ebp
0x0804870b <+1>: mov %esp,%ebp
0x0804870d <+3>: and $0xfffffff0,%esp
0x08048710 <+6>: sub $0x20,%esp
0x08048713 <+9>: movl $0x0,0x1c(%esp)
0x0804871b <+17>: cmpl $0x0,0x1c(%esp)
0x08048720 <+22>: je 0x804872b
0x08048722 <+24>: mov 0x1c(%esp),%eax
0x08048726 <+28>: add $0x4,%eax
0x08048729 <+31>: jmp 0x8048730
0x0804872b <+33>: mov $0x0,%eax
0x08048730 <+38>: mov %eax,(%esp)
0x08048733 <+41>: call 0x80486df
0x08048738 <+46>: mov 0x1c(%esp),%eax
0x0804873c <+50>: add $0x4,%eax
0x0804873f <+53>: mov %eax,(%esp)
0x08048742 <+56>: call 0x80486b4
0x08048747 <+61>: mov $0x0,%eax
0x0804874c <+66>: leave
0x0804874d <+67>: ret

Dump of assembler code for function main:
0x0804870a <+0>: push %ebp
0x0804870b <+1>: mov %esp,%ebp
0x0804870d <+3>: and $0xfffffff0,%esp
0x08048710 <+6>: sub $0x20,%esp
0x08048713 <+9>: movl $0x0,0x1c(%esp)
0x0804871b <+17>: cmpl $0x0,0x1c(%esp)
0x08048720 <+22>: je 0x804872b
0x08048722 <+24>: mov 0x1c(%esp),%eax
0x08048726 <+28>: add $0x4,%eax
0x08048729 <+31>: jmp 0x8048730
0x0804872b <+33>: mov $0x0,%eax
0x08048730 <+38>: mov %eax,(%esp)
0x08048733 <+41>: call 0x80486df
0x08048738 <+46>: mov 0x1c(%esp),%eax
0x0804873c <+50>: add $0x4,%eax
0x0804873f <+53>: mov %eax,(%esp)
0x08048742 <+56>: call 0x80486b4
0x08048747 <+61>: mov $0x0,%eax
0x0804874c <+66>: leave
0x0804874d <+67>: ret
这是windows平台的:

[plain]
wmain:
004114D0 push ebp
004114D1 mov ebp,esp
004114D3 sub esp,0DCh
004114D9 push ebx
004114DA push esi
004114DB push edi
004114DC lea edi,[ebp-0DCh]
004114E2 mov ecx,37h
0041

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇POJ 2421 Constructing Roads 下一篇打印螺旋序列

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·如何理解c语言指针和 (2025-12-27 01:19:11)
·为什么C标准库没有链 (2025-12-27 01:19:08)
·玩转C语言和数据结构 (2025-12-27 01:19:05)
·MySQL 基础入门视频 (2025-12-26 23:20:22)
·小白入门:MySQL超详 (2025-12-26 23:20:19)