什么是逗号运算符的正确使用?

我看到了这个代码:

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

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

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

在你的例子中,它没有任何理由。 写作时有时是有用的

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

– 那么你不需要花括号。 但这是对灾难的邀请。

逗号运算符是将两个或两个以上的expression式放在引用只允许一个的位置。 在你的情况下,没有必要使用它; 在其他情况下,例如在一个while循环中,它可能是有用的:

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

其中while循环的实际“评估”仅在最后一个expression式上进行pipe理。

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

 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` } 

它也可以用于只能放置单个expression式的地方,但是想要发生两件事情。 例如,以下循环在for循环的第三个组件中递增x并递减y:

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

不要去寻找它的用途,但是如果它是合适的,不要害怕使用它,并且如果你看到其他人使用它,不要被抛出循环。 如果有两件事情没有理由不成为单独的陈述,那就把它们分开陈述,而不是使用逗号运算符。

逗号运算符允许在预期的地方分组expression式。

例如,在某些情况下它可能是有用的:

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

但在你的情况下,没有理由使用它。 这会令人困惑…就是这样…

就你而言,这只是为了避免花括号:

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

指向逗号运算符文档的链接。

逗号操作符的主要用途是混淆; 它允许做两件事情,只有读者只有期望。 最常见的用途之一 – join副作用,属于这一类。 有几种情况可能被认为是有效的,但是:

用于在K&R中显示的那个:在for循环中递增两个variables。 在现代代码中,这可能发生在像std::transformstd::copy这样的函数中,输出迭代器与input迭代器同时递增。 (更常见的是,这些函数当然会包含一个while循环, while循环结尾的单独语句中会有增量,在这种情况下,使用逗号而不是两个语句是没有意义的。

想到的另一个例子是初始化器列表中input参数的数据validation:

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

(假设validate( param )会在出错的时候抛出一个exception)。这个用法不是特别有吸引力,特别是因为它需要额外的括号,但是没有多lessselect。

最后,我有时看到了这个约定:

 ScopedLock( myMutex ), protectedFunction(); 

,这避免了必须为ScopedLock创build一个名称。 说实话,我不喜欢它,但是我已经看到了它的使用,另外增加额外的支撑,以确保ScopedLock立即被破坏也不是很漂亮。

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

首先:考虑一个expression式:

  x = ++j; 

但暂时来说,如果我们需要分配一个临时的debugging值,那么我们可以写。

  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使用的问题中,代码不工作 ,错误地,OP忘了写函数的名字,而不是写tokens = strtok(NULL, ",'"); 他写了tokens = (NULL, ",'"); 他没有得到编译错误 – 但它是一个有效的expression式, tokens = ",'"; 在他的节目中造成了无限循环。

在你的情况下,逗号操作符是无用的,因为它可以用来避免大括号 ,但是由于作者已经把它们放在了上面,所以不是这种情况。 因此它是无用的,可能会令人困惑

()运算符的实际用法似乎很less。

Bjarne Stroustrup,C ++的devise和演变

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

使用boost :: assign时 ,我发现了一个有趣的用法,它明智地重载了操作符,使其performance为逗号分隔的值列表,可以将其推送到vector对象的末尾

 #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 } 

不幸的是,一旦编译器开始支持统一初始化,现在stream行的用于原型的上述用法现在看起来就显得过时了

所以这让我们回到了

()运算符的实际用法似乎很less。

Bjarne Stroustrup,C ++的devise和演变

boost::assign重载逗号操作符来实现这种语法:

 vector<int> v; v += 1,2,3,4,5,6,7,8,9; 

如果您想在条件为时执行两条或更多条指令,那么对于行程操作符可能很有用。 但请记住,由于逗号操作符从左到右的评估规则(我的意思是在括号内), 返回值将是最正确的expression式

例如:

 a<b?(x=5,b=6,d=i):exit(1);