如果我遇到if (!this) return;
了应用程序中的旧代码,这有多严重的风险?它是危险的滴答定时炸弹,需要立即在应用程序范围内进行搜索并破坏工作,还是更像是一种可以悄悄放置的代码气味?
当然,我不打算编写执行此操作的代码。相反,我最近在一个旧的核心库中发现了一些东西,供我们的应用程序的许多部分使用。
想象一个CLookupThingy
类具有非虚拟 CThingy *CLookupThingy::Lookup( name )
成员函数。显然,在那个牛仔时代,一位程序员遇到过多次崩溃,这些崩溃CLookupThingy *
是从函数传递NULL的,而不是修复数百个调用站点,而是安静地修复了Lookup():
CThingy *CLookupThingy::Lookup( name )
{
if (!this)
{
return NULL;
}
// else do the lookup code...
}
// now the above can be used like
CLookupThingy *GetLookup()
{
if (notReady()) return NULL;
// else etc...
}
CThingy *pFoo = GetLookup()->Lookup( "foo" ); // will set pFoo to NULL without crashing
我本周早些时候发现了这颗宝石,但现在在是否应该修复它方面发生了冲突。这位于我们所有应用程序使用的核心库中。这些应用程序中有几个已经交付给数百万个客户,并且看起来运行良好。该代码没有崩溃或其他错误。删除if !this
查找功能将意味着修复成千上万个可能传递NULL的呼叫站点。不可避免地会遗漏一些,引入新的错误,这些错误会在下一年的开发中随机弹出。
因此,除非绝对必要,否则我倾向于将其保留。
鉴于这是技术上未定义的行为,if (!this)
实际上有多危险?是否值得花几个星期的时间进行修复,还是可以依靠MSVC和GCC来安全返回?
我们的应用程序在MSVC和GCC上编译,并在Windows,Ubuntu和MacOS上运行。与其他平台的可移植性无关。保证所讨论的功能永远不会是虚拟的。
编辑:我正在寻找的客观答案是这样的
- “ MSVC和GCC的当前版本使用ABI,其中非虚拟成员实际上是带有隐式'this'参数的静态变量;因此,即使'this'为NULL,它们也将安全地分支到函数中”或
- “即将发布的GCC版本将更改ABI,以便即使非虚拟函数也需要从类指针中加载分支目标”或
- “当前的GCC 4.5具有不一致的ABI,有时它将非虚拟成员编译为带有隐式参数的直接分支,有时又编译为类偏移函数指针。”
前者表示代码很臭,但不太可能破坏;第二是在编译器升级后要测试的东西;后者甚至需要付出高昂代价立即采取行动。
显然,这是一个等待发生的潜在错误,但是现在我只关心减轻特定编译器的风险。