堆栈内存分配

3
据说在C/C++中,局部变量将在函数结束时自动分配和释放。
据我理解,当被释放时,局部变量所持有的值也会被销毁!如果我错了,请纠正我。
考虑以下代码:
void doSomething(int** num)
{
  int a = 10;
  *num = &a;
} // end of function and a will be destroyed

void main()
{
  int* number;
  doSomething(&number);
  cout << *number << endl;  // print 10 ???
}

请问有人可以为我澄清一下吗?


4
呃,不要使用 void main() - wkl
3
它仅打印 10 是因为该值尚未被其他内容覆盖。只是因为运气好看起来能正常工作。 - Gabe
1
@Josh:那样做没有帮助,特别是如果 OP 正在调试模式下运行。 - John Dibling
4个回答

8

您说得对。您的cout语句可能打印10,也可能不打印。这将导致未定义的行为。


为了更好地说明,请在您的编译器上运行以下代码,并禁用所有优化选项。

#include <iostream>
using namespace std;

void doSomething(int** num)
{
    int a = 10;
    *num = &a;
}

void doSomethingElse() {
    int x = 20;
}

int main()
{
    int* number;
    doSomething(&number);
    doSomethingElse();
    cout << *number << endl; // This will probably print 20!
}

我认为用户538042得到了10分,这就是发帖的原因。 - Shamim Hafiz - MSFT
+1,尽管 cout 可能实际上会打印 10。或者它可能打印 -34528719849,格式化硬盘或召唤鼻部恶魔。 - suszterpatt
如果在 doSomething(&number); 之后立即调用 cout << *number << endl;,并且没有涉及到多线程,我敢打赌它总是会打印出10。 - a1ex07
1
@a1ex07:不是的。有优化编译器、中断和带有内核线程的操作系统。 - ruslik
+1,但是:它可能打印10。它甚至可能在二十年内一直打印10,然后在单个重要机器上失败。这就是“未定义行为”的问题,通常它不够未定义。我冒昧改变了你的措辞以达到这个效果。 - peterchen
显示剩余2条评论

5
在这种情况下,整数a在堆栈上。您正在将该变量的地址返回给主程序。调用后该地址位置上的值是未定义的。可能在某些情况下,如果堆栈的那部分没有被覆盖,它可以打印10(但你肯定不想依赖它)。

1

指向的内存已被释放回系统。这意味着它将保持其原有的值,直到系统将该内存块分配给另一个变量并用新值覆盖它。

局部变量在超出作用域时被释放。如果您正在尝试使用 out 参数将值返回给函数:

void doSomething(int** num)
{
  int* a = new int;
  *a = 10;
  *num = a;
}

int main()
{
  int* number = 0;
  doSomething(&number);
  std::cout << *number << std::endl;  // print 10 ???
  if (number) delete number;
}

不过,对于这么简单的事情,最好还是直接这样做:

int doSomething()
{
  return 10;
}

int main()
{
  std::cout << doSomething() << std::endl;
}

@Zac:就我而言,对于第一个示例,我只能说“呕”。真的有必要向新手灌输分配内存和依赖调用者再次释放内存的奇妙思想吗? :) 致OP——阅读《Effective C++》,我记得它在这个特定点上有一个很好的条目。此外,这本书本身也很不错。 - Stuart Golodetz
@Zac,有趣,你在删除之前检查了,但没有在取消引用之前检查! - Nim
@Stuart:这更多是为了回答他的问题。他不能在堆栈上分配一个项目并将该项目的内存位置传递回来,使其有效。这就是第二个示例的原因。 - Zac Howland
@Nim:那只是为了演示目的。他可以看到内存中的值(无论是否有效)。 - Zac Howland
@Zac:如果你正在向他展示如何做某事,最好一开始就向他展示正确的方法,而不是那些以后会让他吃亏的方法。Nim的观点也很好,因为删除空指针是一个无操作。 - Stuart Golodetz
@Stuart:我做了...第二个例子是他应该为这么简单的事情所做的。至于检查,对于标准内存管理器来说是正确的。如果您使用自定义内存管理器,则不总是如此。这更多是习惯而已。我完全同意Meyer和Sutter的书是OP寻找答案的好地方。 - Zac Howland

1

内存的内容实际上并没有被销毁。 对于这种情况,num将指向一个未分配给任何变量的位置,但它将保留其内容,该内容已设置为10。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接