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

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

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

Почему ты бы так поступил? Почему не просто

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

35

Решение

В вашем примере это не имеет никакого смысла. Это иногда полезно, когда написано как

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

— тогда ты не необходимость Фигурные скобки. Но это приглашение к катастрофе.

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

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

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

54

Другие решения

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

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
}

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

19

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

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

Другой случай, который приходит на ум, — проверка данных входных параметров.
в списке инициализаторов:

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

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

Наконец, я иногда видел соглашение:

ScopedLock( myMutex ), protectedFunction();

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

4

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

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

   x = ++j;

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

   x = DEBUG_VALUE, ++j;

Во-вторых:
запятая , операторы часто используются в 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 = ",'"; вызвал бесконечный цикл в своей программе.

4

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

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

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

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

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

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

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

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

4

По-видимому, практического использования оператора, () мало.

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

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

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

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

2

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

1

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

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