您的位置:首页 > 编程语言 > C语言/C++

C++中,函数声明时指针、引用相关的语义,定义方法原型时参考。

2008-09-16 20:57 661 查看
一门语言,包括语法、语义。通常计算机书籍上只会讲语法规则。这几年下来,发现讲语义的书籍太少太少(也许是我很久不看书了^_^)。本文抛砖引玉,罗列一些与函数声明相关的常见语义。



函数在调用时,将参数压栈,返回值则拷贝给调用者。如果是简单类型,事情很简单,但是牵扯到指针或者引用,事情就会复杂一些,因为在C/C++中,由程序员负责管理内存和资源,一个优秀的程序员必须清楚的了解自己代码内,每一次内存申请及对应的释放在什么时候发生。



比如下面这个声明:



struct MyDate

{

int year;

int month;

int day;

};



void GetBirthday(MyDate * pBirthday);

请问pBirthday这个指针,谁负责申请空间,谁负责释放空间?

这个问题其实比较简单,因为参数压栈时将指针本身压栈,指针所指地址并不在栈中,显然应该由调用者负责申请内存,对应的,应该由调用者释放内存。



如果我们把函数声明改一下,如果返回一个指针怎么理解?

MyDate * GetBirthday(void);



常规理解,函数负责申请内存,调用者负责释放。



但是。。。但是。。。如果GetBirthday()的实现不常规呢?



static MyDate myBirthday;

...

...



MyDate * GetBirthday(void)

{

return &myBirthday;

}

如果调用者delete 返回的指针,程序行为不确定。嘿嘿,所谓行为不确定,就是在你这里程序运行好好的,在客户那里一定会崩溃的行为。

可能有看官要问,为啥返回一个指针呢?为啥不直接返回MyDate对象呢?

在返回对象时,编译器会为我们生成一个不可见的临时对象,供调用者使用,所以如果声明成

MyDate GetBirthday(void);

与返回指针的声明相比,在C代码中,会多一次结构拷贝,在C++代码里,会多一次拷贝构造,多一次析构。在某些追求效率的场合,这些多余的操作很难容忍。此外,如果你的对象里有资源、内存管理,在析构时很有可能将资源、内存意外释放掉。

有同学说,反正是公司内部的代码,调用者看一下实现不就结了吗?

问题在于:

1、你要求别人看你的实现,增加别人的负担,你是在给别人挖坑;

2、如果你的代码是编译成库,供别人使用怎么办?你的公司不愿意泄露源代码怎么办?



作为折衷,可以把函数声明成

const MyDate * GetBirthday(void);



const的语义,就是告诉调用者,这个指针归我管,你不要乱动。





由于对象传递时编译器会自动生成拷贝语句,所以往往我们都是传递对象指针或者对象引用,下面罗列一些常见的相关语义,供大家参考:

一个方法接受普通指针,表明这个方法可能会修改这个指针指向的数据;
一个方法接受常量指针,表明这个方法承诺不会修改这个指针所指向的数据;
一个方法返回普通指针,表明这个方法要求调用者负责释放这个指针;
一个方法返回常量指针,表明这个方法会自己处理这个指针所指空间,调用者不需要费心;

一个方法接受普通引用,表明这个方法可能会修改这个引用的数据;
一个方法接受常量引用,表明这个方法承诺不会修改这个引用的数据;

一个方法返回普通引用,表明这个方法期望或者允许调用者修改返回的对象;
一个方法返回常量引用,表明这个方法不允许调用者修改返回的对象;





这些东西看着很琐碎,有同学可能会说:这么多条条框框,编码彻底成了体力活儿。



但是没办法,我们要注意,代码是写给人看的,不是写给编译器看的,切记切记。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐