Как правильно использовать оператор запятой?

Я видел этот код:

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

зачем вы это сделали? Почему не просто:

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

9 ответов


в вашем примере это не служит никакой причине вообще. Это иногда полезно, когда написано как

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

-- тогда вы не нужно фигурные скобки. Но это приглашение к катастрофе.

оператор запятой должен поместить два или более выражений в положение, где ссылка позволяет только одно. В вашем случае, нет необходимости использовать его; в других случаях, например в цикл while, это может быть полезно:

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

где фактическая "оценка" while loop управляется исключительно на последнем выражении.


законные случаи оператора запятой редки, но они существуют. Один из примеров - когда вы хотите, чтобы что-то произошло внутри условной оценки. Например:

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

Он также может использоваться в местах, где вы можете разместить только одно выражение, но хотите, чтобы произошло две вещи. Например, следующий цикл увеличивает x и уменьшает y в третьем компоненте цикла for:

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

Не ищите его использования, но если это так соответствующий, Не бойтесь использовать его, и не бросайте для цикла, если вы видите, что кто-то другой использует его. Если у вас есть две вещи, у которых нет причин не быть отдельными операторами, сделайте их отдельными операторами вместо использования оператора запятой.


основное использование оператора запятой-обфускация; это позволяет делать два там, где читатель ожидает только одного. Один из самых частых использует-добавление побочных эффектов к условию, подпадает под это категория. Есть несколько случаев, которые можно считать допустимыми, однако:

тот, который использовался для представления его в K&R: увеличение двух переменные for петли. В современном коде это может произойти в функция, как std::transform или std::copy, где итератор вывода есть увеличивается symultaneously с входной итератор. (Чаще конечно, эти функции будут содержать while петли, с инкрементации в отдельных операторах в конце цикла. В таких случаи, нет смысла использовать запятую, а не два оператора.)

еще один случай, который приходит на ум-это проверка данных входных параметров в списке инициализаторов:

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

(предполагается, что validate( param ) выдаст исключение, если что-то не так.) Этот использование не особенно привлекательно, особенно поскольку ему нужны дополнительные скобки, но альтернатив не так много.

наконец, я иногда видел конвенцию:

ScopedLock( myMutex ), protectedFunction();

, что позволяет избежать необходимости изобретать имя для ScopedLock. Сказать правда, мне это не нравится, но я видел, как его использовали, и альтернатива добавления дополнительных фигурных скобок, чтобы гарантировать, что ScopedLock сразу разрушенное тоже не очень красиво.


это можно лучше понять, взяв несколько примеров:

первый: Рассмотрим выражение:

   x = ++j;

но на данный момент, если нам нужно назначить временное значение отладки, мы можем написать.

   x = DEBUG_VALUE, ++j; 

второй:
Запятая!--5--> операторы часто используются в for() -цикл например:

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, ",'"); и он не получал ошибку компиляции ,но это действительное выражение, которое tokens = ",'"; вызвал бесконечный цикл в его программе.


оператор запятой позволяет группировать выражение там, где оно ожидается.

например, это может быть полезно в некоторых случаях :

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

но в вашем случае нет причин использовать его. Это сбивает с толку... вот и все...

в вашем случае, это просто, чтобы избежать фигурные скобки :

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

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

ссылку оператор запятая документация.


в вашем случае оператор запятой бесполезен, так как он мог быть использован, чтобы избежать фигурные скобки, но это не так, так как писатель уже поставил их. Поэтому это бесполезно и может ввести в заблуждение.


Кажется, что существует несколько практических применений оператора, ().

Бьярне Страуструп, дизайн и эволюция C++

большую часть использования запятых можно найти в статье Википедии Comma_operator#Использует.

одно интересное использование, которое я узнал при использовании 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
}

к сожалению, вышеупомянутое использование, которое было популярным для прототипирования, теперь будет выглядеть архаичным, как только компиляторы начнут поддерживать Инициализации

Так что остается нам вернуться к

Кажется, что существует несколько практических применений оператора, ().

Бьярне Страуструп, дизайн и эволюция C++


на boost::assign сильно перегружает оператор запятой для достижения такого синтаксиса:

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

Это может быть полезно для оператор маршруту Если вы хотите выполнить две или больше инструкций, когда условие true или false. но имейте в виду, что возвращаемое значение будет