为什么在将 const 指针初始化为 null 时没有警告或错误?

Why is there no warning or error when initializing a const pointer to null?

这可能是一个非常基本的问题,但我试图在 SO 中找到答案,但找不到确切的答案。

nullptr初始化一个const指针有什么意义?

int *const pi = nullptr;

为什么编译器没有发出警告或错误,为什么指针 pi 不能在程序的任何地方有效使用?

我试过用g++ -w编译这个。

此外,您能否给出一些用例,其中 const 指针将在实际代码中出于有效目的初始化为 nullptr

不要混淆 const,意思是:“初始化后值不能改变”和“在任何情况下这个值总是 nullptr”。我的意思是:

 struct foo {
     int *const pi = nullptr;
     foo( int* p) : pi(p) {}
 };

foo 的不同实例对于 pi 可以有不同的值。

另一种初始化条件的方法是:

 int *const pi = (some_condition) ? nullptr : some_pointer;

即使是普通的

 int *const pi = nullptr;

没有错。它基本上是给 nullptr 一个不同的名称,因此您可以在任何可以使用 nullptr 的地方使用 pi。例如作为容器中的哨兵:

 int * const empty = nullptr;
 for ( int* element : container) {
     if (element != empty) do_something(element);
 }

这可能被认为是混淆,直接使用 nullptr 会更具可读性。尽管稍后考虑哨兵值的变化,然后使用 empty make 很容易替换它的所有出现。

虽然我同意初始化指向 nullptrconst 指针 通常 特别有用,但有一种情况 可能 我合适的是 有条件地 定义 const pi 指向 nullptr 或其他(有效)地址的指针,具体取决于编译-时间设置,如下例所示。 (const 限定符可防止其他代码无意中更改值,从而破坏上述编译时条件。)

#include<iostream>  

#define USENULL 1 // Comment out this line to get a 'valid' pointer!

int main()
{
    int a = 42;
    #ifdef USENULL
    int* const pi = nullptr;
    #else
    int* const pi = &a;
    #endif
    int* pa = pi;
    if (pa) std::cout << *pa;
    else std::cout << "null pointer";
    std::cout << std::endl;
    return 0;
}

例如,当您需要区分调试版本和发布版本时,可能会出现这种情况。

我将尝试概括@AdrianMole 的(第二个)示例:

有时,一段代码是更通用指令或模式的退化案例离群案例。因此:

  • 在@AdrianMole 的示例中,有一个源外参数控制 pi 是否应该具有有意义的值。你不想为了适应这种情况而扭曲你的源代码太多,所以你保留相同的代码但使用 nullptr,可能稍后(运行-时间)检查你是否有没有nullptr.

  • 您可能有一个模板 class,其中的一般定义类似于:

    template <typename T>
    class A  {
    int *const pi = whatever<T>();
    }
    

    具有专业化

    template <>
    class A<foo_t>  {
    int *const pi = nullptr;
    }
    

    因为您想避免调用 whatever<foo>().

很可能可以改进此类代码以避免显式 nullptr 赋值。但是通过警告来迫使开发人员这样做有点过分了。

(错误是不可能的,因为就语言标准而言,它是完全有效的代码。)