48

我看到了这段代码:

if (cond) {
    perror("an error occurred"), exit(1);
}

为什么要这么做?为什么不只是:

if (cond) {
    perror("an error occurred");
    exit(1);
}
4

9 回答 9

63

在您的示例中,它根本没有任何理由。当写成时它有时很有用

if(cond)
  perror("an error occured"), exit(1) ;

-- 那么你就不需要花括号了。但这是灾难的邀请。

逗号运算符是将两个或多个表达式放在引用只允许一个的位置。在您的情况下,无需使用它;在其他情况下,例如在 while 循环中,它可能很有用:

while (a = b, c < d)
  ...

其中 while 循环的实际“评估”仅由最后一个表达式控制。

于 2013-07-27T22:21:16.867 回答
21

逗号运算符的合法情况很少见,但确实存在。一个例子是当你想在条件评估中发生一些事情时。例如:

std::wstring example;
auto it = example.begin();
while (it = std::find(it, example.end(), L'\\'), it != example.end())
{
    // Do something to each backslash in `example`
}

它也可以用于只能放置一个表达式,但希望发生两件事的地方。例如,以下循环在 for 循环的第三个组件中递增 x 并递减 y:

int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
    // Do something which uses a converging x and y
}

不要去寻找它的用途,但如果合适的话,不要害怕使用它,如果你看到其他人在使用它,也不要陷入循环。如果您有两件事没有理由不成为单独的语句,请将它们分开,而不是使用逗号运算符。

于 2013-07-27T22:19:31.607 回答
6

举一些例子可以更好地理解这一点:

首先: 考虑一个表达式:

   x = ++j;

但是暂时,如果我们需要分配一个临时的调试值,那么我们可以写。

   x = DEBUG_VALUE, ++j; 

第二:
逗号,运算符经常在for()-loop中使用,例如:

for(i = 0, j = 10; i < N; j--, i++) 
 //      ^                   ^     here we can't use ;  

第三:
再举一个例子(实际上可能会觉得这样做很有趣):

if (x = 16 / 4), if remainder is zero then print  x = x - 1;  
if (x = 16 / 5), if remainder is zero then print  x = x + 1;

也可以一步完成;

  if(x = n / d, n % d) // == x = n / d; if(n % d)
    printf("Remainder not zero, x + 1 = %d", (x + 1));
  else
    printf("Remainder is zero,  x - 1 = %d", (x - 1));

PS:知道有时使用 ,运算符是灾难性的也可能很有趣。例如,在问题Strtok usage, code not working中,错误地,OP 忘记写函数的名称,而不是写tokens = strtok(NULL, ",'");,他写了tokens = (NULL, ",'");,他没有得到编译错误——但它是一个有效的表达式,tokens = ",'";导致无限循环他的节目。

于 2013-07-28T05:51:25.727 回答
5

逗号运算符允许将表达式分组到预期的位置。

例如,它在某些情况下很有用:

// In a loop
while ( a--, a < d ) ...

但在你的情况下,没有理由使用它。会很混乱……就是这样……

在你的情况下,这只是为了避免花括号:

if(cond)
    perror("an error occurred"), exit(1);

// =>
if (cond)
{
    perror("an error occurred");
    exit(1);
}

逗号运算符文档的链接。

于 2013-07-27T22:23:51.360 回答
5

逗号运算符的主要用途是混淆;它允许做两件读者只期望一件的事情。最常见的用途之一——给病情增加副作用,属于这一类。然而,有一些情况可能被认为是有效的:

用于在 K&R 中呈现它的一个:在for循环中增加两个变量。在现代代码中,这可能发生在类似std::transform或的函数中std::copy,其中输出迭代器与输入迭代器同时递增。(当然,更常见的情况是,这些函数将包含一个while循环,在循环结束时在单独的语句中递增。在这种情况下,使用逗号而不是两个语句是没有意义的。)

另一个想到的情况是初始化列表中输入参数的数据验证:

MyClass::MyClass( T const& param )
    : member( (validate( param ), param) )
{
}

(这假设如果validate( param )出现问题会抛出异常。)这种用法并不是特别有吸引力,特别是因为它需要额外的括号,但没有很多替代方案。

最后,我有时会看到约定:

ScopedLock( myMutex ), protectedFunction();

,这避免了必须为ScopedLock. 说实话,我不喜欢它,但我已经看到它使用过,并且添加额外的大括号以确保ScopedLock立即破坏的替代方法也不是很漂亮。

于 2013-07-27T22:57:12.390 回答
2

运算符 () 的实际用途似乎很少。

Bjarne Stroustrup,C++ 的设计与演进

大多数常用的逗号可以在维基百科文章Comma_o​​perator#Uses中找到。

我在使用boost::assign时发现了一个有趣的用法,它明智地重载了运算符,使其表现为逗号分隔的值列表,可以推到向量对象的末尾

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

{
    vector<int> values;  
    values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container
}

不幸的是,一旦编译器开始支持统一初始化,上述在原型设计中流行的用法现在看起来已经过时了

所以这让我们回到

运算符 () 的实际用途似乎很少。

Bjarne Stroustrup,C++ 的设计与演进

于 2013-07-28T08:24:53.793 回答
1

在您的情况下,逗号运算符是无用的,因为它可以用来避免花括号,但事实并非如此,因为作者已经放了它们。因此它是无用的,可能会令人困惑

于 2013-07-27T22:23:59.893 回答
1

如果您想在条件为truefalse时执行两个或多个指令,它可能对行程运算符很有用。但请记住,由于逗号运算符从左到右评估规则,返回值将是最右边的表达式(我的意思是在括号内)

例如:

a<b?(x=5,b=6,d=i):exit(1);
于 2014-12-26T16:28:56.647 回答
0

boost::assign重载逗号运算符以实现这种语法:

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;
于 2013-08-26T10:02:38.403 回答