【问题标题】:Is nullptr falsy?nullptr 是假的吗?
【发布时间】:2019-08-16 15:19:33
【问题描述】:

当用作布尔表达式或显式或隐式转换为布尔值时,nullptr 是否始终为假?此实现是否在标准中定义或指定?

我写了一些代码来测试,但不确定它是否完全测试了这个属性。我找不到专门讨论此问题的现有 SO 答案。 cppreference 在我看到的情况下并没有提到这一点。

if (nullptr) {
    ;
} else {
    std::cout << "Evaluates to false implicitly\n";
}

if (!nullptr) {
    std::cout << "Evaluates to false if operated on\n";
}

if (!(bool)(nullptr)) {
    std::cout << "Evaluates to false if explicitly cast to bool\n";
}

预期和实际:

Evaluates to false implicitly
Evaluates to false if operated on
Evaluates to false if explicitly cast to bool

【问题讨论】:

标签: c++ c++11 language-lawyer implicit-conversion nullptr


【解决方案1】:

根据 C++ 17 标准(5.13.7 指针文字)

1 指针字面量是关键字 nullptr。它是类型的prvalue std::nullptr_t。 [注意:std::nullptr_t 是一个独特的类型,它是 既不是指针类型也不是指向成员的指针类型;而是一个prvalue 这种类型是一个空指针常量,可以转换为 空指针值或空成员指针值。见 7.11 和 7.12。 — 尾注]

和(7 次标准转换)

4 某些语言结构需要转换表达式 为布尔值。 出现在这种上下文中的表达式 e 是 据说在上下文中转换为 bool 并且是格式良好的 if 和 仅当声明 bool t(e);结构良好,对于一些发明 临时变量 t (11.6)。

最后(7.14 布尔转换)

1 算术纯右值、无范围枚举、指针或 指向成员类型的指针可以转换为 bool 类型的纯右值。一种 零值、空指针值或空成员指针值是 转换为假;任何其他值都将转换为 true。 为 直接初始化 (11.6),std::nullptr_t 类型的纯右值可以是 转换为 bool 类型的纯右值;结果值为假。

那是你可以写的例子

bool b( nullptr );

但你可能不会写(尽管一些编译器有一个与此相关的错误)

bool b = nullptr;

因此,nullptr 可以在上下文中转换为 bool 类型的对象,例如在 if 语句等选择语句中。

让我们以 if 语句中的一元运算符 ! 为例

if ( !nullptr ) { /*...*/ }

根据运算符的描述(8.5.2.1 一元运算符)

9 逻辑否定运算符的操作数!是上下文的 转换为 bool(第 7 条);如果转换后,它的值为真 操作数为假,否则为假。结果的类型是bool

所以nullptr 在这个表达式中没有被转换为指针。它直接根据上下文转换为布尔值。

【讨论】:

    【解决方案2】:

    保证你的代码结果,[dcl.init]/17.8

    否则,如果初始化为直接初始化,则源类型为std​::​nullptr_­t,目的类型为bool,被初始化对象的初始值为false。

    这意味着,对于直接初始化,bool 对象可以从nullptr 初始化,结果值为false。那么对于(bool)(nullptr),nullptr 被转换为bool,值为false。

    当nullptr作为if的条件或者operator!的操作数时,被认为是contextual conversions,

    如果声明 bool t(e); 格式正确,则执行隐式转换

    这意味着if (nullptr) 和!nullptr,nullptr 都将转换为bool,值为false。

    【讨论】:

    • 这是一个错误的答案。 std::nullptr_t 是一种独特的类型,既不是指针类型也不是指向成员的指针类型。 nullptr t 是一个空指针常量,可以根据上下文转换为 bool。
    【解决方案3】:

    是的,但你应该避免使用这个事实。

    比较指向false 或0 的指针是C/C++ 编码中的常见比喻。我建议您避免使用它。如果要检查是否为空,请使用:

    if (x == nullptr) { /* ... */}
    

    而不是

    if (!x) { /* ... */}
    

    或

    if (not x) { /* ... */}
    

    第二个变体给读者增加了一点困惑:x 是什么?它是一个布尔值吗?一个普通的值(例如一个整数)?指针?一个可选的?即使x 有一个有意义的名称,它也对你没有多大帮助:if (!network_connection) ...它仍然可以是一个复杂的结构,可以转换为整数或布尔值,它可能是一个布尔指示符,指示是否存在连接,它可以是指针、值或可选值。或者别的什么。

    此外,记住 nullptr 的计算结果为 false 是您需要存储在大脑后部以正确解码您正在阅读的代码的另一位信息。我们可能从过去或阅读其他人的代码就习惯了它——但如果我们不习惯,nullptr 的行为就不会很明显。从某种意义上说,其他模糊的保证并没有什么不同,比如the value at index 0 of an empty std::string is guaranteed to be \0。除非万不得已,否则不要让你的代码依赖这些东西。


    PS : 现在空指针的使用实际上少了很多。如果他们不需要,您可以force pointers to never be null;您可以使用引用而不是指针;您可以使用std::optional&lt;T&gt; 返回T 或“no T”。也许您可以完全避免提及nullptr。

    【讨论】:

    • 我非常不同意你的建议。 C 是关于如何,C++ 是关于what。这就是为什么你有auto:这意味着你不需要知道类型。在同一行中,if (!network_connection) 是明确的,您不必关心network_connection 是可转换为bool 的类还是指针。 C++ 中的代码应该表达程序员的意图。
    • @Mirko:即使你对“what”感兴趣,但“not x”仍然常常让人感到困惑。
    猜你喜欢
    • 2010-10-02
    • 2013-06-11
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    相关资源
    最近更新 更多