第5.4章: nullptr

English

概述

指针必须始终存储以下二者之一:

在本章中,你将学到:

1. 什么是 nullptr?

nullptr 是一个特殊值,含义是:

“这个指针不指向任何对象。”


int *p = nullptr;   // p points to nothing

这是表示空指针或未初始化指针的正确方式。

2. 为什么需要 nullptr

在 C++11 之前,程序员用 0 或 NULL 表示空指针。 这些做法有问题:

nullptr 修复了所有这些问题。它有自己的类型:


std::nullptr_t

并且它只会转换为指针类型。

3. 始终用 nullptr 初始化指针

未初始化的指针含有一个不可预测的地址。 使用它是未定义行为。


// Bad: uninitialized pointer
int *p;

// Good: always initialize
int *q = nullptr;

之后,当你有了真实的对象,就赋上它的地址:


#include 

int value{42};
int *p = ::std::addressof(value);

4. nullptr 没有地址

空指针不指向任何内存位置。


p:
Address: 4000
Memory: [ null ]   ← p stores “no address”

指针本身位于内存中的某处,但它的值是“没有地址”。

5. 打印 nullptr

在 fast_io 中,直接打印 nullptr_t 值会输出 字符串 "nullptr"。


#include <fast_io.h>
#include <cstddef>

std::nullptr_t np = nullptr;
println(np);     // prints: nullptr

如果你想要空指针的数值表示,请使用 pointervw:


#include <fast_io.h>
using namespace ::fast_io::iomnp;

println(pointervw(nullptr));

这会打印指针宽度的完整数值地址,零扩展到平台的 指针大小。例如在 64 位系统上:


0x0000000000000000

这能确保所有指针(包括空指针)的格式化一致。

6. 不能解引用 nullptr

空指针不指向任何对象。 你不能解引用 nullptr。


int *p = nullptr;

// *p = 10;   // undefined behavior — never do this

解引用 nullptr 永远是未定义行为。

7. 未定义行为并不保证会崩溃

许多初学者以为解引用 nullptr 一定会崩溃。 这是错的。

未定义行为的含义是:

编译器可能假定指针永不为空

现代编译器会积极优化代码。 它们可能假定某个指针永不为空,从而移除检查或重排代码。

未启用内存标记的 WebAssembly 不会陷入陷阱

在 WebAssembly 上,如果没有启用内存标记,解引用 nullptr 通常不会触发陷阱。 虚拟机无法高效检测空指针解引用,因此程序可能带着被破坏的状态 继续运行。

这就是解引用 nullptr 极其危险的原因。

8. nullptr 在比较中

你可以检查一个指针是否为空:


int *p = nullptr;

if (p == nullptr)
{
    // p does not point to anything
}

这常用于解引用之前:


if (p != nullptr)
{
    int x = *p;   // safe
}

9. nullptr 与指向指针的指针

指向指针的指针类型也可以为空。


int **pp = nullptr;

// **pp;   // undefined behavior — pp does not point to a pointer

10. 使用 sanitizer 检测空指针解引用

现代编译器提供了在运行时检测空指针解引用的工具。

AddressSanitizer


-fsanitize=address

可检测:

内存标记(WebAssembly)


-fsanitize=memtag

可检测:

这些工具让指针缺陷更容易被发现和修复。

要点