【问题标题】:Why is there no warning or error when initializing a const pointer to null?为什么将 const 指针初始化为 null 时没有警告或错误?
【发布时间】:2020-12-17 09:08:31
【问题描述】:

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

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

int *const pi = nullptr;

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

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

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

【问题讨论】:

  • 因为 nullptr 不是无效的。我猜对于像“pi”这样的数值来说,它并没有什么意义,但这是你作为开发人员的选择。它仍然是有效的代码。举个例子,我可以想象有一个(const)指针故意为空(永远),因为根据类的实例化某些功能被禁用。
  • nullptr 是一个有效的指针值,没有理由不应该被允许。 if(something == pi) 仍然有效。
  • "pi 不能在程序的任何地方有效使用。"你为什么这么认为?我可以在任何可以使用nulltpr 的地方有效使用。没有错,只是给nullptr起一个不同的名字不是很有用
  • 为什么要禁止这个?同样,您可以说为什么应该禁止 (true and false and true and false) 之类的东西,因为无论如何它的计算结果为 false。没有标准来检查您的语义。
  • 规范性文件中没有任何内容需要在这种情况下进行诊断,因此没有“应该”。如果有的话,您声明了一个合法的不可变空对象(模式)

标签: c++ pointers null nullptr


【解决方案1】:

不要混淆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使得替换它的所有出现很简单。

【讨论】:

    【解决方案2】:

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

    有时,一段代码是更一般的指令或模式的退化案例异常案例。因此:

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

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

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

      专业化

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

      因为你不想打电话给whatever&lt;foo&gt;()

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

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

    【讨论】:

      【解决方案3】:

      虽然我同意将const 指针初始化为nullptr 并不是一般特别有用,但可能我适合的一种情况是你会有条件地 定义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;
      }
      

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

      【讨论】:

      • 我认为第一个例子不合适。屏蔽nullptr 以节省一些击键是错误的编码习惯恕我直言。考虑只保留第二个,它更有效。
      • @einpoklum 同意 - 我们不想鼓励在 SO 上的不良编码实践!编辑删除。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多