为什么/何时使用 (!!p) 而不是 (p != NULL)?

7
在以下代码中,使用(!!p)而不是(p != NULL)的好处是什么?
AClass *p = getInstanceOfAClass();
if( !!p )
  // do something
else 
  // do something without having valid pointer

23
我想知道为什么仅使用 if (p) 不行。 - GManNickG
3
你应该始终怀疑运算符被重载。!p!=可能具有特殊行为。 - Kobi
2
Kobi - 我记不清了,但是重载运算符是否也适用于对象的指针?似乎它们不会;如果我是正确的,在这种情况下就没有真正的重载运算符问题。(无论我是否正确,这都是一个很好的观点,值得+1) - Twisol
1
它们确实可以使用 Object* operator+(Object const*, Object const*) 作为有效的签名... - Matthieu M.
1
@Twisol: 不,你第一次说得对。运算符不能为非类/非枚举类型重载。非成员重载不会改变任何东西。如果你想声明它,可以这样做,但是重载决议将永远不会考虑它。在原始示例(指针类型)中,运算符重载是不可能的。 - AnT stands with Russia
显示剩余4条评论
7个回答

11

这两种写法基本相同,但是我认为!!p不好,通常表明编码者试图过于聪明。


5
如果你用了一个小时来编写这个聪明的代码,在几周后你需要花两个小时来理解它。 - Twisol
2
我完全同意。应该是“试图聪明,但失败了”。 - Wernsey

9

实际上,这是一种风格问题,它们是等价的。请参见这个非常相似的问题进行讨论。

在我看来,与空指针进行比较更加清晰易懂。


7

我认为GMan的原始评论应该被接受为答案:

我想知道仅使用 if (p) 有什么问题

关键是:没有任何问题,这应该是首选的方式。首先,!!p 太聪明了;它也完全不必要,因此是错误的(请注意:我们在这里谈论指针在 if 语句中的情况,因此 Anacrolix 的评论虽然通常有效,但在这里不适用!)。

p != NULL 也是如此。虽然这是可能的,但是它只是不需要的。它是多余的代码,使代码变得更糟糕。Jeff Atwood 曾经说过:“最好的代码就是没有代码。” 避免冗余的语法。坚持最小化(仍然传达完整含义;if (p) 是完整的)。

最后,if (p) 可以说是在 C++ 中编写此类代码的最习惯用法。C++ 为语言中的其他类型(例如数据流)倒退弯腰,以获取相同的行为,代价是一些非常奇怪的怪癖。下一个标准版本甚至引入了新的语法,以在用户定义的类型中实现此行为。

对于指针,我们可以免费获得相同的功能。所以使用它。

/EDIT:关于清晰度:sharptooth 写道

我认为与 null 指针进行比较更清晰。

我认为这是客观错误的:if (p) 更清晰。在 C++ 中,在此上下文中或任何其他情况下都不可能有任何其他含义。


我明白了。如果(p)就可以做到所有的事情,它简短、清晰。(有些人可能还会称其为不使用“NULL”的额外好处,因为他们更喜欢“0”)。 - stijn
2
我更喜欢将 if (x) 保留给布尔类型,而将 if (x != nullptr /* 或 NULL */) 保留给指针类型。这样你的指针检查在代码中会更加突出,并且易于搜索。 - Bill
"这个语句不可能有其他的意思。" - 同样,如果 (p != NULL),也没有任何其他的可能性,只能是 p 不等于 NULL,不管 NULL 是什么。 - Ed S.
@Ed:是的,但p!= NULL提供了冗余信息。与if(p)相比有什么好处? - Konrad Rudolph

3
据我所知,这只是一种将其转换为布尔值的更短的方法。它应用了两次!,而p != NULL只进行了一次比较。因此,我想好处只是更短的代码,尽管如果你不知道!!p的含义,它可能会更加神秘。

-1

它们是相同的,但我建议使用

NULL != p

这样更易读。


4
可读性有待商榷。个人而言,我认为它不够易读,因为它的表达不够自然。通常我会说“如果p不是NULL”,而不是“如果NULL不是p”。 - Bojan Resnik
3
是的,但这可以防止人们错过一个错误的“p = NULL”,因为编译器会检测到“NULL = p”。 - ChrisBD
2
@ChrisBD:我知道的任何编译器都会捕捉到“p = NULL”。除非你禁用了警告,但你永远不应该这样做。 - DevSolar
1
我同意这种写法比双重否定更易读,但是我反对你声称它比!!pp != NULL都更易读。那些忽略警告的开发者应该花费数小时来寻找“条件中的赋值”错误——这样做没有其他原因,只是为了学会不要忽略警告。像DevSolar一样,我也强烈反对为懒散的开发实践引入变通方法。 - Bojan Resnik
1
OP: '使用 (!!p) 而非 (p != NULL) 有什么好处?' Catalin: '它们是相同的,但我建议使用 NULL != p。这更易读。'也许只是我的理解,但我认为'Catalin'实际上想表达 'NULL != p比这两个都更易读。' - Bojan Resnik
显示剩余9条评论

-1

在给定的示例中没有区别。

然而,假设这适用于所有情况是不正确的。就整数类型而言,a = not not b 不等同于 a = b

在 C 中,0 为假。除了 0 以外的任何值都为真。但是 not 01,没有其他值。在 C++ 中,true 转换为 1 作为整数,这不仅是为了与 C 向后兼容,而且因为 1 不是 0,并且 1 是用于表示 C bool 类型中的 true 的最常见值,包括 official C bool type 和 Win32 中使用的 BOOL

虽然对于给定的示例代码,!!p 是不必要的,因为结果被转换为 bool 以评估 if 条件,但这并不排除使用 !! 将布尔值转换为预期的整数值。就个人而言,在这个例子中,为了最大化类型更改和语义清晰的可能性,我会使用 NULL != pp != NULL 来明确表示意思。

这种技术被称为双重否定习惯用语,this guy provides some good justifications


这些辩解在这种情况下是无效的。 - Keith Randall
实际上,在这种情况下,if(p)和if(!!p)是相同的。这是因为“if”的条件被转换为bool并进行测试,这正是!!最终要做的。关于链接的答案,在C++中,内核开发人员可以将其值转换为bool。 - Richard Corden
虽然对于给定的示例代码,!!p 显然不是必要的,但或许我应该更清晰地表达这一点。 - Matt Joiner

-2

不要使用双重否定。一个简单的论点是,由于C++是英语的有限子集,而英语本身并没有双重否定,因此英语母语者将会很难解析发生了什么。


除非你也学过拉丁语,否则双重否定——根据上下文——并不会被取消,而是否定的含义会被放大。 - MP24
2
除了这个之外!(C++是英语的有限子集)。 - outis
@MP24?能举个例子吗?我只知道相反的情况(例如“non ignoro”),双重否定用于强调肯定的断言(在这种情况下:“我非常清楚”而不是“我不不知道”)。至于英语,“ain't got no money”是完全有效的方言(Steven Pinker甚至将其用作例子),其中(在意义上)双重否定被省略,以简单否定代替:“no”取代了“any”。同样的情况也适用于(标准)法语,“je n'ai pas d'argent”字面上翻译为“I haven't got no money”,但意思是相反的。</离题> - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接