我可以使用 if (pointer) 而不是 if (pointer != NULL) 吗?

Posted

技术标签:

【中文标题】我可以使用 if (pointer) 而不是 if (pointer != NULL) 吗?【英文标题】:Can I use if (pointer) instead of if (pointer != NULL)? 【发布时间】:2013-07-20 06:35:33 【问题描述】:

通过简单地编写if(pointer) 来检查指向不是NULL 的指针是否安全,还是我必须使用if(pointer != NULL)

【问题讨论】:

事实是,如果您要使用显式检查,那么与0nullptr 进行测试同样有效——而且通常是首选。 (NULL 是 C'ism,需要包含头文件。) @danijar 你可以在现代 C++ 中使用 nullptr。 @cHao “力求与 C 兼容”的意义何在? @danijar: 是的,你不应该在 C++ 中使用 NULL,因为 NULL 是依赖于实现的宏,它可能会给你带来模棱两可的行为。 虽然这不是 'if' 的情况,但请参阅这个 ideone 现场演示,了解为什么在 C++ 中应避免使用“NULL”和“0”指针:ideone.com/tbvXNs 【参考方案1】:

你可以;空指针被隐式转换为布尔值 false 而非空指针被转换为 true。来自 C++11 标准,布尔转换部分:

算术、无范围枚举、指针或指向成员类型的指针的纯右值可以转换为 类型的prvalue bool。零值、空指针值或空成员指针值转换为 false; 任何其他值都转换为 true .类型的prvalue std::nullptr_t 可以转换为prvalue 类型 bool ;结果值为 false .

【讨论】:

【参考方案2】:

是的,你可以。

空指针被隐式转换为 false 非空指针被转换为真。

这是C++标准转换的一部分,属于布尔转换子句:

§ 4.12 布尔转换

算术纯右值、无作用域枚举、指针或指向成员类型的指针可以转换为布尔类型的纯右值。 将零值、空指针值或空成员指针值转换为false;任何其他值都转换为 true。 std::nullptr_t 类型的纯右值可以转换为 bool 类型的纯右值;结果是假的。

【讨论】:

【参考方案3】:

是的,你可以。事实上,我更喜欢使用if(pointer),因为一旦你习惯了它,它就更容易读写了。

另请注意,C++11 引入了nullptr,它优于NULL

【讨论】:

指针不是布尔表达式。它是隐式转换的。如果最好阅读时必须记住此转换才能理解是您的意见。这只是一种编码风格。 @harper 你可以说这是一种编码风格。但是您可以将相同的逻辑应用于if(som_integer)if(some_integer != 0),因为整数也不是布尔值,对吧?我更喜欢在 if 语句中避免使用 0NULL 我同意这只是编码风格的问题。我自己更喜欢if (pointer),但if (ptr != nullptr) 对我来说似乎完全合法。另一方面,如果我在团队中看到有人写了if (some_integer),我会让他们将其更改为if (some_integer != 0)。但是,我不会假装这不是我的一个相对武断的偏好——我只是不想把指针和整数一视同仁。 @YuHao 既然是代码风格,我不会说“它是首选”而是“我更喜欢”。 @franji1 那么if(isReady)if(filePtr)if(serviceNo)呢?在这种情况下,故意制作错误的变量名并没有多大意义。无论如何,我已经明白了你的意思,但我可以坚持自己使用自己的编码风格,好吗?【参考方案4】:

问题已回答,但我想补充一点。

我将永远喜欢if(pointer) 而不是if(pointer != NULL)if(!pointer) 而不是if(pointer == NULL)

简单、小巧

编写错误代码的机会更少,假设我将相等检查运算符 === 拼写错误if(pointer == NULL) 可能拼写错误 if(pointer = NULL) 所以我会避免它,最好只是 @ 987654331@.(我也推荐了一些Yoda condition in one answer,但那是另一回事)

while (node != NULL && node->data == key) 类似,我将简单地写成while (node && node->data == key),这对我来说更明显(表明使用短路)。

(可能是愚蠢的原因)因为NULL是一个宏,如果假设有人错误地用其他值重新定义。

【讨论】:

使用 = 而不是 == 几乎总是会产生编译器警告,在人们不会使用 if ( NULL == ptr ) 的日子里, @paulm 我刚刚添加了这一点,它被称为Yoda Condition 有些人不喜欢它,因为它的可读性较差。 (boolean expression)? true : false 完全没有意义。该表达式的计算结果为truefalse;你说的是“如果是真的,给我真,如果是假的,给我假”。简而言之:它完全等同于布尔表达式本身。请注意,node == NULL 是一个布尔表达式。顺便说一句,您的两个实现返回的结果正好相反。要么你想要!= 在第一个,要么只在第二个! 顺便说一句,针对= 而不是== 的一种可能保护措施是尽可能使您的变量const。例如,您可以将您的函数定义为isEmnpy(node* const head) ... ,然后如果您不小心写了node = NULL 而不是node == NULL,编译器将拒绝编译它。当然,这只适用于您确实不需要更改的变量。 因为智能指针类有T* get() const 而不是operator T*() const 以避免隐式转换。然而,他们确实有一个operator bool() const【参考方案5】:

显式检查 NULL 可以为编译器提供有关您尝试执行的操作的提示,从而减少出错的可能性。

【讨论】:

【参考方案6】:

是的,你可以。隐式地将值与零进行比较的能力是从 C 继承来的,并且存在于所有版本的 C++ 中。您也可以使用if (!pointer) 来检查指针是否为NULL。

【讨论】:

【参考方案7】:

空指针的相关用例是

重定向到更深的树节点,可能不存在或尚未链接。您应该始终将这些内容紧密封装在一个专用类中,因此可读性或简洁性在这里不是什么大问题。

动态演员表。将基类指针转换为特定的派生类(您应该再次尝试避免,但有时可能会发现有必要)总是成功,但如果派生类不匹配,则会导致空指针。一种检查方法是

Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr)  ... 

(或者,最好是auto derived_ptr = ...)。现在,这很糟糕,因为它将(可能无效,即 null)派生指针留在了安全防护 if 块的范围之外。这不是必需的,因为 C++ 允许您在if-condition 中引入布尔可转换变量

if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr))  ... 

这不仅更短且范围安全,而且其意图也更加清晰:当您在单独的 if 条件中检查 null 时,读者想知道“好的,所以 derived_ptr 在这里不能为 null。 ..好吧,为什么它会是空的?”而单行版本非常明确地说“如果您可以安全地将base_ptr 转换为Derived*,那么将其用于...”。

对于任何其他返回指针的可能失败操作同样适用,尽管 IMO 您通常应该避免这种情况:最好使用 boost::optional 之类的东西作为可能失败操作结果的“容器”,而不是指针。

因此,如果空指针的主要用例应始终以隐式强制转换样式的变体编写,我会说出于一致性原因始终使用这种样式是好的,即我会提倡if(ptr) 而不是if(ptr!=nullptr)


恐怕我不得不以一个广告结尾:if(auto bla = ...) 语法实际上只是对此类问题的真实解决方案的一个稍微麻烦的近似:模式匹配。你为什么要先强制一些动作(比如投射指针)然后考虑可能会失败......我的意思是,这很荒谬,不是吗?这就像,你有一些食物,想要做汤。如果它碰巧是一种软蔬菜,你把它交给你的助手来榨汁。你不先看它。当你有一个土豆时,你仍然会把它交给你的助手,但他们会用失败的说明把它打回你的脸上。啊,命令式编程!

更好:立即考虑您可能遇到的所有情况。然后采取相应的行动。哈斯克尔:

makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato..) = mash (boil p) <> water
makeSoupOf vegetable
 | isSoft vegetable  = squeeze vegetable <> salt
makeSoupOf stuff  = boil (throwIn (water<>salt) stuff)

Haskell 还提供了一些特殊工具,用于在确实存在严重失败的可能性时(以及用于一大堆其他东西):monads。但这不是解释这些的地方。

&langle;/advert&rangle;

【讨论】:

在这个没完没了的长篇大论中,我只能看到一句话真正回答了这个问题。 @EJP:如果您从字面上理解这个问题(“可以我使用”),那么根本没有明确回答(答案只是“是”)。我试图给出正确的理由说明为什么 OP 应该 实际上使用 if(ptr) 而不是 if(ptr != nullptr),对此还有很多话要说。【参考方案8】:

是的。事实上你应该。如果您想知道它是否会创建 segmentation fault,它不会。

【讨论】:

【参考方案9】:

是的,当然! 事实上,写 if(pointer) 是一种比 if(pointer != NULL) 更方便的写法,因为: 1.易于调试 2. 容易理解 3.如果不小心定义了NULL的值,那么代码也不会crash

【讨论】:

【参考方案10】:

由于其他人已经回答得很好,它们都是可以互换的。

不过,值得一提的是,在某些情况下您可能想要使用显式语句,即pointer != NULL

另见https://***.com/a/60891279/2463963

【讨论】:

【参考方案11】:

是的,两者在功能上是相同的。但在 C++ 中,你应该切换到 nullptr 来代替 NULL;

【讨论】:

【参考方案12】:

是的,您始终可以这样做,因为“IF”条件仅在其内部条件为真时才进行评估。 C 没有布尔返回类型,因此当条件为真时返回非零值,而当 'IF' 中的条件结果为假时返回 0。默认返回的非零值是1。因此,两种编写代码的方式都是正确的,而我总是更喜欢第二种。

【讨论】:

如果我没记错的话,默认的非零值是未定义的。【参考方案13】:

我认为根据经验,如果您的 if-expression 可以重写为

const bool local_predicate = *if-expression*;
if (local_predicate) ...

这样它不会导致任何警告,那么这应该是 if-expression 的首选样式。 (我知道当我将旧的 C BOOL (#define BOOL int) 分配给 C++ bool 时会收到警告,更不用说指针了。)

【讨论】:

【参考方案14】:

“安全吗..?”是关于语言标准和生成代码的问题。

“是一个好习惯吗?”是一个关于该陈述的任意人类读者对该陈述的理解程度的问题。如果您问这个问题,则表明“安全”版本对未来的读者和作者来说不太清楚。

【讨论】:

我的目的是询问它是否安全。所以我用了这个词。但是,您在这里写的并不是问题的答案。相反,它应该是问题下的评论。您可以删除答案,然后在问题下添加评论。 @danijar 你不记得你刚接触 *** 并且搜索“评论”部分没有成功吗?声望为 7 的人无法做到这一点。 @JimBalter 这很令人困惑,因为您可以看到其他人这样做。当我刚接触 SO 时,有人指责我这样做。 @JimBalter 我不是在谋杀和偷窃。我告诉 danijar Fred Mitchell 是新用户,不能发布 cmets。 @JimBalter 你今天开始的。你也是一个不理解的人。该评论仅支持对此的混淆。

以上是关于我可以使用 if (pointer) 而不是 if (pointer != NULL) 吗?的主要内容,如果未能解决你的问题,请参考以下文章

C 下标值不是数组、指针或向量 - 是吗?

如果我使用 lambda 而不是 If 块,是不是会有性能损失?

为啥我应该使用 continue 而不是空的 if 语句? [关闭]

为啥使用预处理器#if 语句而不是 if() else?

java,时间单独的if语句和循环而不是带有探查器的方法

Twig 中是不是有任何方法可以确定方法/参数是不是存在而不将 if 放在任何地方?