探讨C++中的引用和指针

   abstract: C++中的指针和引用是对容易搞错的概念,昨天一个同事问起,作了一些探讨, 今天整理一下。
   
   keyword:引用  指针  原子类型  对象
 
   contents:
   以Q/A的形式记录,并作一些分析。
Q:一位同事问我,此函数有问题么?
char *strcpy(char *strDest, const char *strSource)
{
    char *s = strDest;
    while((*strDest++ = *strSource++)!='/0');
    return s;
}
A:(我战战兢兢,是不是有什么玄机)如不考虑越界问题是对的。
 
Q:然后改之:
char& strcpy(char *strDest, const char *strSource)
{
    char &s = *strDest;
    //while((*strDest++ = *strSource++)!='/0');
    return s;
}
A:返回外部变量的引用,也没有问题呀。
 
Q:C++ Primer上介绍说是这样是有问题的,书上的例子大概是
string& function(const string &net)
{
    string s = net;
    //do someting
    return s;
}
A:返回局部变量的引用,当然会出问题, 与上面的代码有本质的区别。
 
Q:他又整了一段代码,
char& function(void)
{
    char c = 'a';
    char &r_c = c;
    //do sometiong
    return r_c;
}
(
注:此函数相当于
char& function(void)
{
    char s;
    //someting to do with s.
    return s;
}
可以这样理解:
char* function(void)
{
    char s;
    //someting to do with s.
    return &s;
}
对熟悉指针的一看就知道,此函数有问题。
)
int main(int argc, char* argv[])
{
    char &s = function();
    printf("%c", s);
    return 0;
}
你看, 程序没有问题,能调试过。
A:虽然s的值仍为'a', 但是这个区域已经不在程序控制之内(堆栈已经释放,即栈顶指针变了)。
如果主函数改为如下, 则s的值就变了。
int main(int argc, char* argv[])
{
    char &s = function();
    printf("%c", s);
    char y;
    printf("%c", s);

    return 0;
}
 
[1]这样调用char s = function();是没有问题的, 此函数相当于
char function(void)
{
    char s;
    //do someting with s.
    return s;
}, 但谁又能保证都这样调用呢, 而且返回引用的函数可以作为=操作符的左侧:function()='d';(比如string类的操作符[]),这样使用是非常危险的。
--------------------------------------------------------------------------
 
扩充:
SQ:以上讨论的是原子类型,如果是对象呢?(牵扯到拷贝与析构的问题)
String & function(void)
{
     String s="hello";
     return s;
}
String function(void)
{
     String s="hello";
     return s;
}
调用语句:string t = function();
A:看汇编代码比较return语句处的差异
第一个函数是先释放s的空间,然后带回引用,再调用拷贝构造把释放的局部变量的值给t。所以从这点来看上面的回答([1]处)是有问题的。
第二个函数是先把s的拷贝构造给t,然后释放s.
 
SQ:operator = 为什么要返回引用呢?
//Assigns one String object to another
String& String::operator=(const String& s)
{
     //Do nothing if left and right sides are same
     if(this != &s)
     {
          _length = s._length;
          _maxlen = s._maxlen;
          delete[] p_c;
          p_c = new char[_maxlen];
          strcpy(p_c, s.p_c);
     }
     return *this;
}
void main()
{
     String s1, s2;
     String s3="nihao";
     s1 = s2 = s3;
     //此处释放临时变量
     char x = 10;
     cout<<"23";
}
A:s5=s6=s7;语句采用右结合的执行顺序,先执行s6=s7, 然后执行s5=s6。
同样看汇编代码比较差异:
1)如果返回引用, 当然没有问题,没有返回局部变量的引用。
2)如果不返回引用, 再return之前会调用构造函数把*this,发给一个临时变量。这样会多生成2个临时变量、多调用2次构造、析构函数。而且不能作为赋值的左部,比如function()='d'就是错误的。
 
btw:翻了一下C++ primer目录,里面介绍了pair、eval(是不是与Scheme中的一样, 从Scheme中引入的么, C++中的开源库boost有lambda),以及已红黑树为结构的Map。下周好好瞧一瞧。
查一下LEA汇编指令。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值