C++ 不可能的 nullptr 调用之谜

C++ Impossible nullptr call mystery

所以我决定在我的项目中摆脱单例并引入依赖注入。我做了所有必要的更改,但遇到了一个小问题:无论我做什么,我的 NetworkService 都会被调用,不管它是否已初始化为 nullptr。我开始调查,我得到了一个不可能的场景。我感到无能为力,我放弃了。我不知道这段代码是如何毫无问题地执行的:

    auto impossible_response = ((NetworkService*)nullptr)->post(
            format_url("/api/data/fetch/"),
            payload.dump(),
            headers);
    log.crit("How did this succeeded? Please help me, Whosebug");

Log message

我正在通过 Gradle 使用 G++ (C++20) 在 ArcoLinux 上编译我的代码。我已经尝试过从头开始重建它,而不使用以前构建的任何缓存。

Even If I try to dereference it on purpose, it DOES succeed.

不,该程序有未定义的行为,这意味着它仍然存在错误,即使它没有明确说明并且“似乎去工作”。这是因为在您的程序中使用 -> 取消引用。

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may just crash.

所以您看到(也许看到)的输出是未定义行为的结果。正如我所说,不要依赖具有 UB 的程序的输出。程序可能会崩溃。

因此,使程序正确的第一步是删除 UB。 然后并且只有那时你可以开始对程序的输出进行推理。


1有关未定义行为的更技术准确的定义,请参阅 this,其中提到:有对程序的行为没有限制.

小魔法。如果函数不访问任何 class 成员,则通过任何无效指针调用它可能会被忽视:

struct A {  void func() {cout<< "hello world"<< endl;} };

int main()
{
  ((A*)(nullptr))->func();
}

不确定标准是怎么说的,但在这种情况下函数的行为主要类似于全局函数

更新
为了预见一些讨论,实验是真理之路。我在不同的模式下制作了模式,debug/release/x64/x32、OS Windows/Solaris、编译器 VisualStudio 2022/2019、Embarcadero、g++,都显示出完全相同的行为。我故意试图让代码失败。所有的结果都是一样的。没有强制从主函数 returned 的成功代码。
这是 Windows 下的 VisualStudio: 这是 Solaris 下的 g++,仅失败了明确 returned 失败 return 代码的版本: