4

假设我有这样的功能:

MyClass &MyFunction(void)
{
  static MyClass *ptr = 0;
  if (ptr == 0)
    ptr = new MyClass;
  return MyClass;
}

问题是在程序退出时,ptr 变量是否会变得无效(即该 ptr 的内容被退出进程清除)?我意识到这个函数会泄漏,但这只是一个简单的例子。

除了指针之外,同样的问题也适用于其他原语。如果我有一个静态整数,该整数的值是在整个退出过程中始终保持不变还是由于静态销毁顺序问题而可变?

编辑:

澄清一下,我想知道静态指针(或任何其他原始类型,如 int 或 float)的内容实际发生了什么,而不是它指向的内存。例如,假设 ptr 指向某个内存地址,我想在其他静态类的析构函数中检查该地址。我可以依赖 ptr 的内容不会改变的事实(即在静态销毁过程中不会清除指针值)吗?

谢谢,乔

4

5 回答 5

6

当您进程退出时,分配给它的所有内存页面将被操作系统释放(其他人可能正在使用的模共享内存页面)。

但是,正如其他人指出的那样,从未调用 MyClass 的析构函数。ptr 指向的值也不会改变。如果你有一个值为 123 的静态 int,那么它的值将保持 123 直到进程生命周期的最后。

于 2008-11-20T15:09:43.103 回答
4

在现代操作系统中,应用程序的所有内存都分配在特定于该应用程序的“堆”上。当应用程序退出时,该堆中的所有内存都将被释放。

因此,内存将被释放,但是MyClass永远不会调用析构函数。如果析构函数负责释放任何非内存资源(文件系统锁是一个常见的例子),这可能是一个问题。

于 2008-11-20T15:06:45.043 回答
3

要回答您更新的问题,我会说是的:您可以依靠在整个静态销毁过程中剩余的静态指针的值。它指向的内存可能已被释放,但指针本身的值应保持不变,除非另一个静态类的析构函数对其进行更改。

于 2008-11-20T15:16:07.380 回答
3

要回答您的问题:

'imagine that the ptr points to some memory address which I want to check in the destructor of some other static class'

答案是肯定的。
您可以看到指针的值(地址)。
如果您没有在指针上调用 delete,您可以查看内容。

静态函数变量的行为方式与静态类变量和全局变量(也称为非本地静态变量)的行为方式相同,因为其中的析构函数将以相反的创建顺序被调用。整数、浮点数和指针(POD) 没有析构函数,因此在删除进程之前它们不会发生任何事情。

POD 对象:数据可以安全地从其他对象(甚至是全局对象)的析构函数中引用。

其他静态对象(即具有析构函数的对象):在一般情况下,在 main() 退出后访问这些对象是不安全的,因为不知道销毁顺序(它与创建顺序相反,但是创建顺序很复杂,请参阅:构造顺序)。可以这样做,但您必须采取明确的预防措施以确保对象仍然存在。

注意:非本地静态:

内存将永远存在,在调用析构函数后对象将无效(注意 POD 没有析构函数)。

注意:堆栈:

仅在离开声明它们的范围之前有效。
弹出堆栈后,如果您尝试访问它,它所在的内存页面可能会被丢弃,从而导致 SEG 错误。

注意:堆:

在您对分配它的指针调用 delete 之前有效。
一旦指针被删除,该值可能是随机的,因为它可能会被重复使用。内存所在的页面也可能被删除。对已丢弃页面的任何访问都将导致 SEG 故障。

于 2008-11-20T16:50:12.730 回答
1

简短的回答是“否”:您的指针在程序退出时不会“变得无效”。即指针值不会自动重置为null,并且不会自动调用它指向的MyClass对象的析构函数。

这是因为指针是“原始类型”,即不是对象。

如果你有一个非局部(即全局或静态)变量,它是一个对象,那么规则是不同的:当程序通过调用 exit() 或从主函数返回时,将调用对象的析构函数。如果程序通过调用 abort() 终止,它将不会被调用。

于 2008-11-20T15:18:41.293 回答