【问题标题】:A reference can not be NULL or it can be NULL?引用不能为 NULL 还是可以为 NULL?
【发布时间】:2019-06-17 17:04:44
【问题描述】:

我从维基百科读到:

“引用不能为空,而指针可以;每个引用都指向某个对象,尽管它可能有效也可能无效。”

但我不相信,因为下面的代码,看一下,编译器没有报错:

class person
{
  public:
    virtual void setage()=0;
};

int main()
{
  person *object=NULL;
  person &object1=*object;
}

请详细说明这一点。

【问题讨论】:

  • 文章可能应该说:“格式良好的程序中的每个引用都指向一个对象。”取消引用空指针当然是错误的。
  • 不要忘记我们最喜欢的关于空引用的故事:gotw.ca/conv/002.htm
  • @GMan:这听起来更好。而且,我在链接的 GOTW 上大笑。 “我不能教他;他被未定义的行为所吸引:”可悲的是,我认识这样的人。
  • 当然,程序格式错误的。主要是因为缺少int
  • 不再...另一个空引用讨论...该标准明确指出 (8.3.2/4) '空引用不能存在于定义良好的程序中'

标签: c++ oop


【解决方案1】:

在您的代码中:

person *object=NULL;
person &object1=*object;

你取消引用一个 NULL 指针,所以你得到未定义的行为。为了回答您的问题,没有 NULL 引用之类的东西。

为了解决您问题的另一部分,仅仅因为程序编译,不能保证它是正确的或它会工作。 C++ 编译器甚至不需要尝试诊断代码包含的错误类型。

【讨论】:

    【解决方案2】:

    person &object1=*object 与说person &object1=NULL 不同。可能编译器不够聪明,无法发现您正在取消引用空指针,但无论如何您都会收到运行时错误。所以它们仍然是真实的;)

    【讨论】:

    • 即使编译器捕捉到了这种情况,也总会有它无法捕捉到的其他情况。如果您通过几种方法传递引用,您将让实际程序与您在代码中进行取消引用的地方相距甚远。这不仅仅是理论上的问题,我已经在生产中看到了。
    【解决方案3】:

    你可以有一个空引用,不知道为什么有人会这么说,这是一些操作的讨厌的副作用。你不能直接创建一个。

    【讨论】:

    • 看到投反对票我不应该感到惊讶,我总能看出什么会激怒地球上那些自以为无所不知却一无所知的愚蠢人。
    • 在实践中可以获得 NULL 引用。每当有人说“你不能有 NULL 引用”时,它应该在格式良好的程序中阅读。除了取消引用 NULL 指针之外,还可以创建一个引用,以便 &ref == NULL 通过进行自初始化:int& ref = ref;(我想结果可以是任何东西,包括 NULL)。 - 我认为涵盖问题的务实方面没有任何问题,但你的回答是模糊的、没有信息的和有争议的(“尽管每个人都这么说,[这里有点胡言乱语]”)。
    • @UncleBens,Null 引用具有语言不支持的含义。我认为 invalid 参考更好地描述了这种情况。这是一个微妙的区别,但我认为争议较小。
    【解决方案4】:

    这会使你的程序崩溃。你试过运行它吗? 做 *object 将尊重一个空指针,所以实际上你的引用永远不会被分配。

    【讨论】:

    • 很好的答案我明白了。
    • 我认为它不会崩溃。只有当您尝试访问 object1 的成员(或方法)时,它才会崩溃。
    • 它可能会崩溃、打印 42 或冒出蓝烟 - 简单地取消对空指针的引用会调用未定义的行为,因此您无法提前知道。
    • 刚刚尝试使用 GCC。我在没有来自编译器的一个字的情况下创建了一个对字符串的“N​​ULL 引用”。仅在尝试调用成员函数时收到 GDB 的分段错误。 IMO,虽然您在技术上“不能拥有” NULL 引用,但当事情不顺利时要注意问题是很重要的。 - 无论如何,答案是错误的。如果某物的行为未定义,无法保证它会崩溃
    【解决方案5】:

    嗯,你可以在 C++ 中做任何想要的事情。另一个例子:

    person &object1 = *( reinterpret_cast<person*>(0) );
    

    您在上述情况下调用了未定义的行为,除了您提到的情况!

    【讨论】:

    • 您是否有理由更喜欢reinterpret_cast 而不是static_cast? (当然,在这种情况下它们的行为相同。)
    • @avakar 这就是我写答案时想到的:)
    【解决方案6】:

    clang 3.5 甚至会在以后可能对引用进行 NULL 检查时发出警告:

    /tmp/person.C:11:6: warning: reference cannot be bound to dereferenced null pointer in well-defined C++ code; pointer may be assumed to
          always convert to true [-Wundefined-bool-conversion]
    if (&object1) {}
    ~~   ^~~~~~~
    1 warning generated.
    

    【讨论】:

      【解决方案7】:

      gcc8 会给出警告:

      警告:编译器可以假设'object1'的地址永远不会是NULL [-Waddress]

      一个小演示:

      #include <iostream>
      
      class person
      {
          public:
              virtual void setage()=0;
      };
      
      int main()
      {
          person *object=NULL;
          person &object1=*object;
      
          if (&object1 == NULL) {
              std::cout << "NULL object1" << std::endl;
          }
      
          if (!(&object1)) {
              std::cout << "NULL object1 " << std::endl;
          }
      }
      

      编译运行输出:

      g++ -std=c++2a -pthread -fgnu-tm -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm -latomic -lstdc++fs && ./a.out

      main.cpp:在函数'int main()'中:

      main.cpp:14:18: 警告:编译器可以假设地址 'object1' 永远不会为 NULL [-Waddress]

       if (&object1 == NULL) {
      
                    ^
      

      main.cpp:18:19: 警告:编译器可以假定地址为 'object1' 永远不会为 NULL [-Waddress]

       if (!(&object1)) {
      
                     ^
      

      空对象1

      空对象1

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-14
        相关资源
        最近更新 更多