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

时间:2013-07-27 22:15:43

标签: c++ c coding-style comma-operator

我看到了这段代码:

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

你为什么这样做?为什么不呢:

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

9 个答案:

答案 0 :(得分:54)

在你的例子中,它完全没有任何理由。当写为

时,它有时很有用
if(cond)
  perror("an error occured"), exit(1) ;

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

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

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

实际&#34;评估&#34; while循环仅受最后一个表达式的控制。

答案 1 :(得分:19)

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

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
}

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

答案 2 :(得分:4)

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

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

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

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

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

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

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

指向comma operator文档的链接。

答案 3 :(得分:4)

逗号运算符的主要用途是混淆;它允许做两个 读者只期望的东西。其中最常见的一个 使用 - 添加副作用的条件,属于这个 类别。有几种情况可能被视为有效, 但是:

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

另一个需要考虑的案例是输入参数的数据验证 在初始化列表中:

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

(假设validate( param )将抛出异常 有些事情是错误的。)这种用途并不是特别有吸引力 因为它需要额外的括号,但没有多少选择。

最后,我有时会看到这个惯例:

ScopedLock( myMutex ), protectedFunction();

,这避免了为ScopedLock创建名称。告诉 事实上,我不喜欢它,但我已经看到它的使用,以及替代方案 添加额外的大括号以确保ScopedLock立即生效 被破坏也不是很漂亮。

答案 4 :(得分:4)

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

<强>首先: 考虑一个表达式:

   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 = ",'";在程序中引起无限循环的有效表达式。

答案 5 :(得分:2)

  

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

     

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

可以在维基百科文章Comma_operator#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
}

不幸的是,一旦编译器开始支持Uniform Initialization

,上面用于原型设计的用法现在看起来很陈旧

让我们回到

  

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

     

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

答案 6 :(得分:1)

在你的情况下,逗号运算符是无用的,因为它本来可以用来避免curly braces,但事实并非如此,因为编写者已经把它们放了。因此它无用且可能令人困惑

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

如果要在条件为 true false 时执行两条或更多条指令,则对行程运算符有用。但请记住,返回值将是最正确的表达式,因为逗号运算符从左到右的evalutaion规则(我的意思是在括号中)

例如:

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