【问题标题】:NULL passed directly to a function expecting a const reference parameter (VC++ 4.2)NULL 直接传递给需要 const 引用参数的函数 (VC++ 4.2)
【发布时间】:2011-09-07 17:12:34
【问题描述】:

我正在查看我在旧代码库中发现的一些东西,我很困惑。

这是一个函数定义:

void vUpdateSequenceDetailsAndIncrement(
            const CallEvent& roCPEvent,
            const CallInfo& roCallInfo,
            BOOL bCreationEvent);

这里被调用:

vUpdateSequenceDetailsAndIncrement(roCPEvent, NULL, FALSE);

这里 NULL 被直接传递给引用参数roCallInfo。该函数最终调用:

vTimeChange(*pSeqDetails, roCPEvent, roCallInfo);

定义:

void vTimeChange(const SequenceDetails& roSequenceDetails,
        const CallEvent& roCPEvent,
        const CallInfo& roCallInfo)

再次将可能为 NULL 的值传递给 roCallInfo。我认为 NULL 不能作为参考传递?有谁知道 VC++ 4.x 是否有某种问题使这种代码没问题?如果 NULL 可以作为引用传递,那么在 vTimeChange 中会发生这样的事情:

roCallInfo.getCallStartTime(); 

这不是像我一样取消引用 NULL 吗

CallInfo * info = NULL;
info->getCallStartTime();

? 无论如何,我可能会在那里放置一个警卫,并让编译器在不必要时将其删除,但我很想深入了解这是如何发生的!

谢谢。

【问题讨论】:

  • @Mark Ransom - 实际上是的。这确实有帮助。我以为我已经阅读了所有这些问题。下面的 c-smiles 答案仍然很有趣。
  • info->getCallStartTime() 的调用不一定取消引用NULL。该语法只会导致info 的地址作为this 传递。如果函数中的第一条语句是if (this == NULL) return,那么就不会有解引用和未定义的行为。

标签: c++ visual-c++ reference null-pointer


【解决方案1】:

取决于在 VC 4.2 中如何定义 NULL

如果只是

#define NULL 0 

那么你实际上已经了解了这个:

vUpdateSequenceDetailsAndIncrement(roCPEvent, CallInfo(0), FALSE);

并且将 CallInfo 类型的 temp var 的引用传递给函数(如果 CallInfo 具有兼容的 ctor)

【讨论】:

  • It is #defined to (0)... 这是否意味着使用roCallInfo.getCallStartTime(); 之类的东西就可以了?显然,这也意味着if(roCallInfo == NULL) 将永远是false
  • 这个if(&roCallInfo == NULL) 会是假的,但是你的这个if(roCallInfo == NULL) 会导致调用CallInfo::operator==(int)
  • Dennis,这意味着CallInfo 有一个构造函数,允许它从int隐式创建。如果它还具有operator== 的定义,那么您与NULL 的比较也将起作用,因为NULL 将再次隐式转换为CallInfo。该程序创建了一个 temporary CallInfo 对象,该对象在它所涉及的语句的持续时间内存在,因此您在该临时对象上调用 getCallStartTime。那是绝对安全的。如果你不想要这种隐式转换,那么标记构造函数explicit
  • 谢谢小伙子们。这很有帮助。
【解决方案2】:

我以为NULL 不能作为引用传递?

有效的引用不能为 null,但无效的引用可以为 null。
您在这里看到的是无效参考

引用不能为空这一事实并不意味着引用比指针更安全,正如您在本例中看到的那样。程序可能导致无效引用的方式有很多种,您的代码就是这样一个例子。

参考维基百科:
事实上,reference 也可以从 invalid 开始。因为引用通常实现为底层指针,所以在指针解引用表达式上初始化引用通常由编译器实现为从指针到引用的底层指针的简单赋值。因此,如果您有一个NULL 指针或指向内存中无效位置的指针,您实际上将有一个指向 NULL 或无效位置的引用。 C++ 纯粹主义者会争辩说,从技术上讲,取消引用 NULL 或无效指针无论如何都会导致未定义的行为,因此这并不违反上面的断言,即引用不能为 null 或指向内存中的任意位置。但是,这忽略了这样一个事实,即在这种情况下,底层实现只是简单地执行了一次“赋值”,并没有对所涉及的内存位置进行访问,因此这种引用的初始化通常不会引起问题,程序员必须注意在实际程序中存在事实上的“无效”引用的可能性。

使用无效引用 roSequenceDetails 最终会导致未定义行为。

【讨论】:

    【解决方案3】:

    如果pSeqDetails 为空,则表达式*pSeqDetails 会导致未定义的行为。任何事情都有可能发生。大多数实现不进行任何特定的检查。在您执行实际需要该对象的操作之前,您的代码似乎可以正常工作,然后它将失败。但是一个实现可能会导致它立即失败。

    【讨论】:

    • 对不起,我的问题还不够清楚......我正在寻找有关“NULL”直接传递是否可以的信息。 *pSeqDetails 已经被保护为 NULL。不过还是谢谢。
    猜你喜欢
    • 2012-02-25
    • 2020-12-11
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多