不要返回局部变量的指针或引用

原因阐述

所谓的不可以返回局部变量的引用或指针,指的是不能返回局部变量的引用或地址给引用或指针。

事实上还是看该局部变量的内存空间是在栈区还是堆区的。若是在栈区,函数调用结束,这块空间就被释放了,其对应的局部变量的指针或引用也就紧跟着销毁了,如果此时接收了返回的局部指针或引用并使用的话,会导致未定义问题,存在着一定的风险。

而如果该局部变量的内存空间是在堆区的,那么当函数调用结束时,函数栈帧被销毁,但堆区的变量并不会被销毁,所以可以继续正常使用。也可以说,如果不返回或者处理这些堆区的局部变量或引用,甚至可能会造成内存泄漏。

案例分析

  • 例1
int& fun()
{
    int a = 10;
    return a;
}  

不可以,尝试返回 a 的地址给引用变量,a是存在栈里的,函数结束调用栈被销毁。

  • 例2
std::string  & getstr()
{
    char *buffer = "abcdef";
    return std::string(buffer);
}

不可以,虽然buffer是在字符常量区,但是这个函数返回的是string类型,string对象还在栈上

  • 例3
int* fun()
{
    int a = 10;
    return &a;
}    

不可以,尝试返回 a 的地址给指针,a是存在栈里的,函数结束调用栈被销毁。

  • 例4
int fun()
{
    int a = 10;
    return a;
}    

可以,函数在返回时,产生一个临时对象,用于存放局部变量a的值的一份临时拷贝

  • 例5
int* fun()
{
    int a = 10;
    int *p = &a
    return p;    
}

不可以,返回的是变量a的地址,而a是在栈区的

  • 例6
char* fun()
{
    char *s = "1sfsdg"; //C语言可以这么写,但C++中必须写成const char*
    return s;
}

可以,相对于返回的是 "1sfsdg" 的地址,而 "1sfsdg" 存储在字符常量区,也就在静态存储区,函数栈帧销毁时并不会跟着释放。不过要注意此时返回的不是char*,而是隐式的cosnt char*

  • 例7
char * getstr()
{
    char buffer[100];
    sprintf_s(buffer, "%d", 1234);
    return buffer;
}

不可以,因为buffer是在栈上的

  • 例8
int  *fun()
{
    int *a = (int*)malloc(sizeof(int));
    return a;
}

可以,动态数组数组的空间在堆上,堆中的数据不会随着栈帧的销毁而释放。

函数返回引用和非引用的区别

  • 函数的返回类型为非引用类型

当函数的返回值类型为非引用类型时,其返回值可以是局部对象,也可以是求解表达式。这是因为函数在返回时其实是先将最终的返回值放到一个临时变量中,然后紧接着函数栈帧销毁,再将这个临时变量作为函数调用的返回值,在主调函数处使用,紧接着临时变量也就释放了。也就是说,在变量接收返回值之前,函数栈帧就已经销毁了,接收的只是一个临时变量的值。

  • 函数的返回类型为引用类型

当函数的返回值类型为引用类型时,不借助临时变量,其返回的就是对象本身。所以千万不要返回局部对象的引用或者指向局部对象的指针。这是因为当函数执行完毕后,系统将会自动释放分配给函数及其内部的局部变量的存储空间。此时局部对象的引用就会指向不确定的内存,返回的指针就变成了不再存在对象的悬空指针。

你可能感兴趣的:(C++,temp,开发语言,c++,c语言)