Стандартные конструкции языка

if

Базовый пример:

1
2
3
4
5
6
7
8
int a = 5, b = 10;
if (a < b) {
    cout << "a < b";
} else if (a == b) {
    cout << "a == b";
} else {
    cout << "a > b";
}

Особенности:

  • Условие обязательно оборачивается в круглые скобки
  • Тело всегда нужно оборачивать в фигурные скобки (есть исключения, но по любому кодстайлу лучше всегда использовать фигурные скобки)
  • В условии можно использовать логические операторы && (и), || (или), ! (не)
  • Логические операнды не обязательно оборачивать в скобки; порядок действий такой же, как и в математике (смотри справку)
1
2
3
if (a < b && a > 0) {
    cout << "a < b AND a > 0";
}
  • Блок else if и else не обязателен
  • Все переменные, созданные внутри блока if, else if или else, видны только внутри этого блока, а затем удаляются
1
2
3
4
5
if (a < b) {
    int c = 42;
    cout << c; // 42
}
cout << c; // Ошибка компиляции
  • В условии можно использовать любые типы данных, которые можно привести к bool (например, int, double, char, объекты классов с перегруженным оператором bool)
1
2
3
if (a) {
    cout << "a is not zero";
}
  • Начиная с C++17, в условии можно использовать инициализацию переменной
1
2
3
if (int c = a + b; c > 10) {
    cout << "a + b > 10";
}

Тернарный оператор

Тернарный оператор (англ. conditional operator) - это сокращенная форма if-else, которая позволяет в одну строку записать условие и возвращаемое значение:

1
2
int a = 5, b = 10;
cout << (a < b ? "a < b" : "a >= b");

Особенности:

  • Обе ветки должны что-то возвращать
  • Результирующее значение в обеих ветках должно иметь одинаковый тип данных, иначе будет ошибка компиляции

switch

Конструкция и ограничения

switch - это конструкция, которая позволяет сравнивать переменную с несколькими значениями:

1
2
3
4
5
6
7
8
9
10
11
int a = 5;
switch (a) {
    case 1:
        cout << "a == 1";
        break;
    case 2:
        cout << "a == 2";
        break;
    default:
        cout << "a is not 1 or 2";
}

Особенности:

  • В каждом case должен быть оператор break, иначе выполнение пойдет дальше по следующим case. Это может быть полезно в случаях, подобных этому:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char c = 'a';
switch (c) {
    case 'a':
    case 'b':
    case 'c':
        cout << "a or b or c is lower";
        break;
    case 'A':
    case 'B':
    case 'C':
        cout << "A or B or C is upper";
        break;
    default:
        cout << "not a or b or c or upper";
}
  • В каждом case можно использовать только базовые типы данных (например, char, enum, int, bool, double). То есть нельзя, например, использовать string или vector.
  • В case можно использовать только константы, то есть нельзя использовать переменные:
1
2
3
4
5
6
7
8
9
int a = 5;
switch (a) {
    case 1:
        cout << "a == 1";
        break;
    case a:
        cout << "a == 5"; // Ошибка компиляции
        break;
}

Быстродействие

Вы можете задаться вопросом: почему у данного оператора так много ограничений? Всё дело в том, что независимо от размера switch любой подходящий case может быть найден за ровно одну операцию, то есть данный оператор не будет размернуть в кучу if-else, вместо этого будет намного эффективнее! Перед тем, как читать дальше, попробуйте самостоятельно ответить на вопрос: как это работает?

Ответ

switch внутри себя использует таблицу переходов, которая хранит адреса всех case. При сравнении переменной с case компилятор сначала сравнивает переменную с case и, если находит совпадение, переходит по адресу из таблицы. Таким образом, время выполнения оператора switch не зависит от количества case и всегда равно O(1).

Циклы

Общие особенности циклов:

  • Любая переменная, объявленная внутри цикла (например, в условии или теле), будет видна только внутри этого цикла и удаляется после его завершения, как и у условного оператора if.
  • Для выхода из цикла можно использовать операторы break (выход из цикла) и continue (переход к следующей итерации цикла). Однако их использование не рекомендуется, так как они могут сделать код менее читаемым (всё зависит от конкретного случая). Вместо этого лучше использовать логические операторы в условии цикла.
  • Важно понимать, что break и continue действуют только на ближайший цикл, в котором они находятся.

while

Самый простой цикл - while. Он будет выполняться, пока условие истинно:

1
2
3
4
5
int a = 0;
while (a < 10) {
    cout << a << " ";
    a++;
}

do-while

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

1
2
3
4
5
int a = 0;
do {
    cout << a << " ";
    a++;
} while (a < 5); // 0 1 2 3 4

for

for - это цикл, который позволяет задать начальное значение, условие и шаг:

1
2
3
for (int i = 0; i < 5; i++) {
    cout << i << " "; // 0 1 2 3 4
}

Особенности:

  • В месте объявления переменной можно объявить несколько переменных через запятую, однако они обязаны быть одного типа:
1
2
3
for (int i = 0, j = 10; i < j; i++, j--) {
    cout << i << " " << j << "\n"; // (0, 10), (1, 9), (2, 8), ..., (4, 6)
}
  • Любой из блоков for может быть пустым:
1
2
3
4
5
int i = 0;
for (; i < 5;) {
    cout << i << " "; // 0 1 2 3 4
    i++;
}
  • Начиная с C++11, можно удобно перебирать элементы в контейнере:
1
2
3
4
vector<int> v = {1, 2, 3, 4, 5};
for (int i : v) {
    cout << i << " "; // 1 2 3 4 5
}

Данный цикл будет равносилен следующему:

1
2
3
for (auto it = v.begin(); it != v.end(); it++) {
    cout << *it << " ";
}

О том, что такое begin и end, вы узнаете в следующих разделах (об итераторах).

  • Начиная с C++20, можно использовать развертывание параметров:
1
2
3
4
map<int, string> m = { {1, "one"}, {2, "two"}, {3, "three"} };
for (const auto& [key, value] : m) {
    cout << key << " " << value << "\n"; // 1 one, 2 two, 3 three
}

Расширения языка

Разные компиляторы поддерживают разного вида расширения стандартных конструкций:

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