在不访问任何数据的 NULL 指针上调用方法是否会失败?

2021-12-23 00:00:00 pointers null methods c++

将程序:

#include <stdio.h>

struct foo
{
   void blah()  {printf("blah
");}
   int i;
};

void main(int, char**)
{
   ((foo*)NULL)->blah();
}

在您知道的任何编译器上,您是否曾经崩溃或执行除输出 blah 以外的任何其他操作?任何函数在通过 NULL 指针调用时,如果不访问任何成员(包括 vtable),是否会崩溃?

Ever crash, or do anything other than output blah, on any compiler you are aware of? Will any function crash, when called via a NULL pointer, if it doesn't access any members (including the vtable)?

关于这个主题还有其他问题,例如 访问类成员NULL 指针 和 调用不通过空指针访问成员的非静态方法是否合法/定义良好的C++?,并且总是指出这会导致未定义行为.但这在现实世界中是未定义的,还是仅在标准世界中没有定义?是否有任何现存的编译器没有按预期运行?你能想出任何可能的原因为什么未来的编译器不会像预期的那样运行吗?

There have been other questions on this topic, for instance Accessing class members on a NULL pointer and Is it legal/well-defined C++ to call a non-static method that doesn't access members through a null pointer?, and it is always pointed out that this results in undefined behavior. But is this undefined in the real world, or only in the standard's world? Does any extant compiler not behave as expected? Can you think of any plausible reason why any future compiler wouldn't behave as expected?

如果函数确实修改了成员,但 NULL ptr 受到保护,该怎么办.例如,

What if the function does modify members, but the NULL ptr is guarded against. For instance,

void foo::blah()
{
   foo* pThis = this ? this : new foo();
   pThis->i++;
}

编辑:作为记录,我想要这样做的原因是使我的链表类的接口尽可能简单和简洁.我想将列表初始化为 NULL 的惯用用法如下:

Edit: For the record, the reason I wanted this was to make the interface to my linked list class as easy and concise as possible. I wanted to initialize the list to NULL have idiomatic usage look like:

pList = pList->Insert(elt);
pList = pList->Remove(elt);
...

所有操作符都返回新的 head 元素.不知何故,我没有意识到使用容器类会让事情变得更容易,而且没有任何缺点.

Where all the operators return the new head element. Somehow I didn't realize that using a container class would make things even easier, with no downside.

推荐答案

你能想出任何可能的原因为什么未来的编译器不会像预期的那样工作吗?

Can you think of any plausible reason why any future compiler wouldn't behave as expected?

有用编译器可能会添加代码以在调试版本中访问引擎盖下的真实对象,希望能帮助您在开发周期的早期在代码中发现这个问题.

A helpful compiler might add code to access the real object under the hood in debug builds in the hope of helping you catch this issue in your code early in the development cycle.

如果函数确实修改了成员,但 NULL ptr 受到保护,该怎么办.例如,

What if the function does modify members, but the NULL ptr is guarded against. For instance,

void foo::blah()
{
   foo* pThis = this ? this : new foo();
   pThis->i++;
}

由于使用空指针调用该函数是未定义的行为,因此编译器可以假定测试将始终通过并将该函数优化为:

Since it is undefined behavior to call that function with a null pointer, the compiler can assume that the test will always pass and optimize that function to:

void foo::blah()
{
   this->i++;
}

请注意,这是正确的,因为如果 this 不为 null,则它的行为 as-if 原始代码已被执行,如果 this> 为空,这将是未定义的行为,编译器根本不需要提供任何特定的行为.

Note that this is correct, since if this is not null, it behaves as-if the original code was executed, and if this was null, it would be undefined behavior and the compiler does not need to provide any particular behavior at all.

相关文章