在 Windows 中初始化静态全局变量时 new 返回 NULL?

Posted

技术标签:

【中文标题】在 Windows 中初始化静态全局变量时 new 返回 NULL?【英文标题】:new returns NULL when initializing static global variable in windows? 【发布时间】:2010-02-12 01:08:40 【问题描述】:

我正在努力将 rLog 与我们的代码库集成,并且我注意到 Windows 上存在一个我在 linux 上没有的问题。在头文件中,我有一个静态变量,它为我提供了一个“详细”的日志记录通道(基本上从调试开始),因此定义:

static RLogChannel *rlog_verbose = DEF_CHANNEL("verbose", Log_Debug);

这在 Linux 上没有问题,但在 Windows 上,应用程序一启动就会出错。

我已经在 rLog 库中追踪到这一行:

RLogChannel *rlog::GetComponentChannel(const char *component, const char* path, LogLevel levl) 
...
if(!gRootChannel)
    gRootChannel = new RLogChannel( "", level );
...

问题是对 new 的调用返回了一个 NULL 指针,它没有被检查 并且程序在被访问时会立即崩溃。是否有与在 Windows 上的全局上下文中分配内存相关的规则?

编辑:我很确定这一定与静态对象的初始化顺序有关。我想确保我没有遗漏一些明显的内容:Windows 上的内存分配。谢谢大家!

【问题讨论】:

new 不能返回 null。你的意思是它抛出一个异常? 您是否检查过代码是否实际执行了,或者 gRootChannel 是否在其他地方只是 NULL? 这两段代码有什么联系?第一个变量名是rlog_verbose,第二个变量名是gRootChannel。有什么联系?有吗? 抱歉,更新得更清楚一点,代码的 sn-p 位于一个因使用 DEF_CHANNEL 宏而被调用的函数中。 @GMan:我不知道 new 抛出了异常,很高兴知道,但我看到对 0x00000000 的无效写入,所以它一定不是 new 调用。可能与静态初始化程序的顺序有关... @GMan:在 Visual Studio 6 中,如果出现错误,new 会返回 NULL。 @gct:你用的是哪个版本的VS? 【参考方案1】:

你确定它返回 null。它可能是整个静态初始化器的事情。静态初始化程序调用的顺序没有在文件之间定义。如果您有使用 rlog_verbose 的静态代码,那么 gRootCHannel 很可能是 NULL,因为尚未调用初始化程序。

【讨论】:

【参考方案2】:

new 不返回 NULL。如果失败,它会抛出 std::bad_alloc 异常。即使它在入口点 CRT 函数中实际调用的静态数据初始化中也会发生这种情况,该函数稍后会调用 main()

您看到的 NULL 可能就在那里,因为从未调用过 new。要验证它是否真正被调用,您只需在静态初始化上放置一个断点并查看它何时发生。

【讨论】:

很高兴知道,我猜这是某种静态初始化问题,我只是很少有 Windows 经验,所以我想确保我没有遗漏一些明显的东西。【参考方案3】:

new 不返回 null。所以你的问题一定是你在静态初始化程序执行之前使用了rlog_verbose。您的静态初始化程序可能从不执行。 (那将是一个链接问题)

您需要启动一个调试器并在您的静态初始化程序、main 以及崩溃的代码行上设置一个中断,然后看看发生了什么。如果您跨过崩溃,它会起作用吗?崩溃发生在main之前吗?

【讨论】:

以上是关于在 Windows 中初始化静态全局变量时 new 返回 NULL?的主要内容,如果未能解决你的问题,请参考以下文章

操作系统中的内存分区

内存的使用:栈区堆区静态区只读区

总结C++静态成员变量的特性总结及测试用例

全局变量和局部变量

C++:全局变量和static变量初始化

静态局部变量