破坏局部变量是什么意思:
void f()
{
int x=10;
}
当该函数调用时,该局部变量的函数结束x
将是什么?
对于:
void f2()
{
int a=100;
int* b=&a;
}
f2()
那个局部变量的值到底是什么b
?指针会b
是一个悬空指针(有地址但没有任何值)吗?
当该函数调用时,该局部变量 x 的函数结束将是什么?
不存在的。蒸发。汽。走了。
x
这是一个具有自动生命周期的变量。“自动”是指当x
超出范围时,它将被销毁。(不完全删除,因为该术语暗示调用delete
)
所有自动变量也是如此,无论它们是整数、字符串、浮点数,甚至是指针:
void f2()
{
int a=100;
int* b=&a;
}
这里a
和b
都是自动变量。它们都将在其作用域结束时被销毁 - f2()
. 但是,将被破坏的只是变量本身。如果一个自动变量是一个指针(例如,一个原始指针),那么指针所指向的东西将不会被破坏。考虑:
void f3()
{
char* p = new char [256];
}
p
这里仍然是一个指针到字符类型的自动变量。p
指向的东西不是自动的——它是动态分配的(我们使用过new
)。
如上所述,p
将被销毁,但它指向的内存不会。这是内存泄漏。为了解决这个问题,您必须delete
:
void f3()
{
char* p = new char [256];
delete [] p;
}
现在指向的内存p
已经被正确销毁,并且指针本身(p
)将在其范围结束时被销毁,因为它是自动的。
生命周期p
和p
指向的内容没有任何联系。仅仅因为你delete
p
并不意味着它p
本身现在也被摧毁了。 p
仍然是一个自动变量。
一个例子:
void f3()
{
char* p = new char [256];
cout << (void*) p << "\n"
delete [] p;
// p still exists, it just points to to nothing useable
cout << (void*) p << "\n"
}
之后delete
,我们将 的值打印p
到屏幕上。如果你运行它,你会看到p
删除它之前的值并没有改变。 p
本身不受delete [] p;
. 但是在f3()
's 的右大括号处}
,它将超出范围并被销毁。
f()
退出时,x
将不复存在。从技术上讲,当然,它所使用的内存仍然存在,但是编译器/系统可以随意使用该内存空间。它最终会将它重用于完全不同的东西。
如果您获取的地址x
并将其从函数中传递出去,那么取消引用该指针是最糟糕的未定义行为。例子:
int* f() {
int a;
return &a;
}
int main() {
int* pointer = f();
//int b = *pointer; //Undefined behaviour, the compiler could choose to format your harddrive now!
}
变量x
, a
, 和b
都是局部变量,因此在函数返回后它们不再存在。x
如果您尝试询问其中任何一个的值是什么,调试器可能会说“在此上下文中找不到”。
更详细地说,这些变量的内存是从堆栈中分配的,并在函数返回时返回到堆栈中。调用f()
本质上是将值 10 放在堆栈顶部的上方;如果您随后int
在未初始化的堆栈上创建另一个,它可能会以值 10 开始(您不应该依赖这种行为,因为它不能保证,但它让您了解堆栈如何在许多系统上工作)。
b
不会是悬空指针,因为您没有在堆上分配任何内存(使用malloc
or new
,它只是指向局部变量地址的指针a
(退出函数范围时被销毁)指针本身也会超出范围。指针f2
在函数结束时被销毁,在这种情况下不会造成内存泄漏,因为它指向的对象在堆栈上并且不是用new
.
但是,如果您考虑以下情况:
int *global;
void foo()
{
int a = 10;
global = &a;
}
然后指针在运行完成global
后存在foo
,但指向一个被销毁的超出范围的变量,其值未定义。
一旦该函数的堆栈帧被弹出......你不能引用那些局部变量
你没有破坏任何东西,你的变量超出了范围。
由于它没有分配堆,因此您不会在内存管理方面遇到任何问题。
如果你真的想学习这种机制的机制,你可以随时下载ollydbg(假设是windows),并在这个函数执行之前、期间和之后进入,以了解现代编程语言和编译器如何处理局部变量.