我今天遇到了一个关于局部变量的问题。我了解到......
int * somefunc()
{
int x = 5;
return &x;
}
int * y = somefunc();
//do something
是坏的,不安全的等等。我想这个案例是相同的......
int * somefunc()
{
int * x = new int;
x = 5;
return x;
}
int * y = somefunc();
//do something
delete y;
我一直认为这是最安全的,因为x的地址在返回时仍然在范围内。但是,我现在有了第二个想法,我认为这会导致内存泄漏和其他问题,就像第一个例子那样。有人可以帮我确认一下吗?
答案 0 :(得分:8)
目前看来,第二个例子是错误的。你可能意味着这个:
int * somefunc()
{
int * x = new int;
*x = 5; // note the dereferencing of x here
return x;
}
现在这在技术上很好,但很容易出错。首先,如果在分配x
之后发生异常,则必须捕获它,删除x
然后重新抛出,否则会出现内存泄漏。其次,如果你返回一个指针,调用者必须删除它 - 调用者忘了。
推荐的方法是返回智能指针,如boost::shared_ptr
。这将解决上述问题。要了解原因,请阅读RAII。
答案 1 :(得分:1)
(编辑)的
是的,第二个没问题,只要你在分配前取消引用'x'!
答案 2 :(得分:1)
您可能只是将int *作为一个示例,但实际上,在您注意到的情况下,没有理由返回int *,只返回int,实际值足够好。我总是看到这些情况,变得过于复杂,何时,实际需要的只是为了简化。
在'int *'的情况下,我只能想到返回一个int数组的现实案例,如果是这样的话,那么你需要分配它,然后在文档中返回,希望它必须被释放。
答案 3 :(得分:1)
第一种方法肯定会导致问题,因为你现在很清楚。
第二种是好的,但要求程序员注意,因为他需要显式删除返回的指针(就像你一样)。当你的应用程序变大时,这会更难,使用这种方法可能会导致问题(内存泄漏),因为程序员会发现很难跟踪他需要解除分配的每个变量。
此方案的第三种方法是在函数内部使用 pass a variable by reference ,这样更安全。
void somefunc(int& value)
{
value = 5;
}
// some code that calls somefunc()
int a_value = 0;
somefunc(a_value);
// printing a_value will display 5
答案 4 :(得分:1)
是的,你冒着泄漏记忆的风险。 (编译错误。) 对int进行此操作是愚蠢的,但即使它是一个大型结构,原理也是一样的。
但要明白:你已经编写了C风格的代码,你可以在其中使用一个分配存储的函数。
如果您正在尝试学习C ++,则应将somefunc()及其操作的数据放入类中。方法和数据在一起。一个类也可以像Space_C0wb0y指出的那样做RAII。
答案 5 :(得分:0)
好的,我会通过回答这些问题来分析这个问题:
- x包含什么? - 内存位置(因为它是一个指针 变量)
- x的范围是什么? - 因为它是一个自动变量,它的范围是 限于函数somefunc()
- 一旦退出本地范围,自动变量会发生什么? - 他们是 从堆栈空间中删除。
- 那么从somefunc()返回后x现在会发生什么? - 因为它是 在堆栈上声明的自动变量 ,它的范围(寿命)仅限于 somefunc()因此将被删除。
- 好的,现在,x指向的值会发生什么?我们有一个 分配值时发生内存泄漏 在堆上,我们刚刚失去了 x被删除时的地址。
- 你得到了什么? - 不知道。
- 删除y后会发生什么? - 不知道。
醇>
答案 6 :(得分:0)
关键是不要返回指向本地变量的指针或引用,因为一旦函数返回,本地就不存在。
但是,返回值仍然存在,并且动态分配的内存当然也存在。
在C ++中,我们希望尽可能避免使用原始指针。要“返回已存在的值”(即函数不创建新值),请使用引用。要“返回一个尚未存在的值”(即函数创建一个新的值,在惯用的意义上,而不是new
关键字的意义上)使用一个值,或者如果需要,使用某种智能指针包装器
答案 7 :(得分:-2)
这是内存泄漏和崩溃(因为删除)。