永远不要返回函数的局部变量的指针或引用,因为函数执行完之后,将释放分配给局部变量的内存,这段内存可能会被回收用作其他用途,也可能暂时不动,这是没法预测的。如果被回收用途其他用途了,那返回的指针就是一个野指针,要么读取的数据是错误的,要么出现内存访问异常错误。如果这段内存暂时还没被回收,那从指针读到的数据也还是正确的,但你没法预料下一秒是否会被回收了。
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> using namespace std;
int *sum(int number1, int number2) { int result = number1 + number2; return &result; }
int main() { int *result = sum(2, 3); cout<< "2 + 3 = " << *result<<endl; return 0; }
|
这段代码在我的电脑上运行就会出现段错误,程序异常终止。
那有时候我们真的需要返回一个局部变量的话,应该怎么办呢?有很多方法可以满足这种需求。
1. 静态局部变量
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> using namespace std;
int *sum(int number1, int number2) { static int result = number1 + number2; return &result; }
int main() { int *result = sum(2, 3); cout<< "2 + 3 = " << *result<<endl; return 0; }
|
静态局部变量存放在内存的全局数据区。函数结束时,静态局部变量不会消失,每次该函数调用时,也不会为其重新分配空间。它始终驻留在全局数据区,直到程序运行结束。静态局部变量的初始化与全局变量类似.如果不为其显式初始化,则C++自动为其初始化为0。
静态局部变量与全局变量共享全局数据区,但静态局部变量只在定义它的函数中可见。
简单来说就是静态局部变量具有全局变量的生命周期,具有局部变量的作用域。
在实际项目中我们一般推荐使用这种方式。
2. 全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <iostream> using namespace std;
static int result; int *sum(int number1, int number2) { result = number1 + number2; return &result; }
int main() { int *result = sum(2, 3); cout<< "2 + 3 = " << *result<<endl; return 0; }
|
在标准库中的 struct tm *localtime (const time_t *__timer)
实现就是返回的全局变量指针。
建议优先考虑静态局部变量,如果非要使用全局变量的话,最好使用 static 把全局变量的作用域限制在本文件内。避免造成命名污染。
3. 动态申请内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> using namespace std;
int *sum(int number1, int number2) { int *result = new int; *result = number1 + number2; return result; }
int main() { int *result = sum(2, 3); cout<< "2 + 3 = " << *result<<endl; delete result; return 0; }
|
使用这种方法需要注意,由于用new申请的动态内存,调用者需要负责释放(delete)这段内存。否则就会造成内存泄漏。
很多内存泄漏问题都是这种动态申请内存后忘了释放内存造成的。所以这种方法我们能避免就尽量避免。避免不了的话,则建议使用智能指针来自动管理内存的释放问题。
4. 智能指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <memory> using namespace std;
shared_ptr<int> sum(int number1, int number2) { shared_ptr<int> result(new int); *result = number1 + number2; return result; }
int main() { shared_ptr<int> result = sum(2, 3); cout<< "2 + 3 = " << *result <<endl; return 0; }
|
这种写法就不需要手动释放分配的内存。但这是 c++ 11 之后才支持的语法。在 android 系统中我们可以使用 sp 智能指针。
对于内存占用比较大的对象来说,推荐使用智能指针。因为系统会自动释放内存, 而使用静态局部变量的话,内存就会一直被占用着。