Все статьи Шпаргалка по C++
Эта статья даёт сжатый обзор основ современного C++. Шпаргалка фокусируется на языке, а не стандартной библиотеке, и учитывает особенности C++11/C++14
Основано на Phillip M. Duxbury’s C++ Cheatsheet, английская версия доработана Morten Nobel-Jørgensen. Дополнения для C++11 основаны на ISOCPP.org C++11 Cheatsheet. Оригинал документа на английском размещён на github.com/mortennobel/cpp-cheatsheet.
Препроцессор
// Комментарий до конца строки
/* Многострочный комментарий */
#include <stdio.h> // Вставить содержимое заголовка, поиск по стандартным путям заголовков
#include "myfile.h" // Вставить содержимое заголовка, поиск начиная с текущего каталога
#define X some text // Замена X на some text
#define F(a, b) a + b // Замена F(1, 2) на 1 + 2
#define X \
some text // Многострочное определение макроса
#undef X // Удаляет определение макроса
#if defined(X) // Условная компиляция (#ifdef X)
#else // Опциональная ветвь else (эквивалент #ifndef X или #if !defined(X))
#endif // Завершает блоки #if, #ifdef
Литералы и переменные
255, 0377, 0xff, 0b1011 // Целые числа (десятичные, восьмиричные, шестнадцатиричные, двоичные)
2147483647L, 0x7fffffffl // Целые числа long (64bit на 64-битных UNIX платформах, 32bit на остальных)
123.0, 1.23e2 // Действительные числа двойной точности (double)
'a', '\141', '\x61' // Символы (литеральный, восьмиричный код, шестнадцатиричный код)
'\n', '\\', '\'', '\"' // Литералы символа переноса строки, обратного слеша, одинарной кавычки, двойной кавычки
"string\n" // Массив символов, завершённый переносом строки и нулевым символом \0
"hello" "world" // Конкатенация двух литералов
true, false // Булевы константы ИСТИНА и ЛОЖЬ
nullptr // Литерал указателя, указывает на нулевой (недопустимый) адрес
Объявления
int x; // Объявление переменной x типа int, т.е. целого числа (значение не определено)
int x = 255; // Объявление переменной и инициализация значением 255
unsigned ing x = 255u; // Объявление переменной типа беззнаковое целое число, инициализация значением 255.
char c = 'a'; // Объявление переменной, хранящей символ (однобайтовый, знаковый или беззнаковый)
unsigned char u = 255; // Объявление переменной типа "беззнаковый символ"
signed char s = -1; // Объявление переменной типа "знаковый символ"
float f; // Знаковое действительное число одинарной точности (обычно 4 байта)
double f; // Знаковое действительное число двойной точности (обычно 8 байт)
bool b = true; // Булевы переменные инициализируются значением true либо false
int a[10]; // Массив из 10 целых числе (индексация начиная с нуля, от a[0] до a[9])
int a[] = { 0, 1, 2 }; // Инициализированный массив (эвивалентно a[3] = { 0, 1, 2 };)
int a[2][2] = { { 1, 2 }, // Двумерный массив, т.е. массив массивов целых чисел
{ 4, 5 } };
char str[] = "hello"; // Строка в стиле языка C (6 элементов, включая '\0' в конце)
std::string str = "Hello" // Строка в стиле C++, инициализированная значением "Hello"
std::string str = R"(Hello
World)"; // Строка в стиле C++, инициализированная значением "Hello\nWorld"
int* ptr = nullptr; // ptr - указатель на адрес в памяти, предназначенный для хранения int
const char* str = "hello"; // str указывает на анонимный массив, хранящий значение "hello\0"
void* ptr = nullptr; // ptr хранит адрес нетипизированной области памяти
int& ref = x; // ref - ссылка на int x (по сути синоним x)
enum Weekend // Weekend - это тип, способный хранить WK_SATURDAY или WK_SUNDAY
{
WK_SATURDAY,
WK_SUNDAY,
};
Weekend day; // day - переменная типа weekend
enum Weekend // На уровне ассембера тип Weekend представлен целым числом,
{ // Здесь для WK_SATURDAY и WK_SUNDAY явно назначаем значения 0 и 1
WK_SATURDAY = 0,
WK_SUNDAY = 1,
};
enum class Color // Современный enum: константы не попадают в глобальную область видимости,
{ // обращаться к ним можно конструкциями Color::Red и Color::Blue.
Red,
Blue,
};
Color color = Color::Red; // Объявляем переменную типа color, инициализируем значением Color::Red.
typedef char* ZeroedString; // Устаревшее добавление синонима типа: объявить `ZeroedString x;` значит объявить `char* x;`.
using ZeroedString = char*; // Современное добавление синонима типа.
const int c = 3; // Константные значения инициализируются один раз и не могут быть повторно присвоены.
const int pow = GetPower(); // Инициализация константы может быть динамической.
const int* ptr = arr; // Нельзя записывать значения в память, на которую указывает ptr (т.е. в элементы arr).
int* const ptr = arr; // Нельзя менять значение указателя ptr (но можно записывать в память, куда он указывает)
const int* const ptr = arr; // Как ptr, так и память, на которую он указывает, недоступны для записи.
const int& cref = x; // cref не получится использовать для изменения x
int8_t, uint8_t, int16_t, // Целые числа с фиксированным числом бит, не зависящим от платформы.
uint16_t, int32_t, uint32_t,
int64_t, uint64_t
auto it = m.begin(); // Объявляем переменную it, тип выставляется автоматически как тип инициализатора m.begin()
auto const param // Объявляем переменную param, тип выставляется автоматически, но будет константным.
= config["param"];
auto& instance // Объявляем переменную instance, тип выставляется автоматически, но будет ссылочным
= singleton::instance();
Классы памяти
int x; // Память для x выделяется автоматически (обычно на стеке) и существует только в области видимости.
static int x; // Память для x выделяется в глобальной области (даже если x объявлена внутри функции).
extern int x; // Переменная x объявлена, но её расположение в памяти будет указано в другом месте.
Инструкции
x = y; // Любое невложенное выражение (включая вызов функции, присваивание) является инструкцией.
int x = 0; // Объявления являются инструкциями.
; // Пустая инструкция.
{ // Блок внутри {} является одной инструкцией
int x; // Области видимости x - от объявления до конца блока.
}
if (x) a; // Если значение x - ИСТИНА (не 0), то выполнить инструкцию print('a');
else if (y) print('b'); // Если не x и y, выполняем print('b'), else if необязателен, его можно повторять;
else print('c'); // Если не x и не y, выполняем print('c') else необязателен.
while (x) // Повторяем 0 или более раз, пока выражение x имеет значение ИСТИНА
print(x);
for (int i = 0; i < 10; ++i)// Эквивалентно `int i = 0; while (i < 10) { doSomething(); ++i; }`
doSomething();
int arr[] = { 5, 10, 20 };
for (auto x : arr) // Range-based цикл for, x последовательно принимает все значения элементов arr.
print(x);
do // Эквивалентно цепочке `foo(); while(x) foo()`;
{
foo();
} while (x);
switch (x) // Switch выполнит прыжок на один из case/default
{ // x должен быть целочисленным типом (enum допускается, строки - нет)
case X1: a; // Если x == X1 (X1 должно быть константой времени компиляции), продолжаем выполнение отсюда
case X2: b; // Иначе если x == X2, продолжаем выполнение отсюда
default: c; // В противном случае продолжаем выполнение отсюда (метка default опциональная)
}
switch (x)
{
case X1:
a;
break; // break прерывает выполнение после метки до конца switch,
default: // если break нет, то после a будет продолжено выполнени и выполнено c, в отличии от инструкции if
c;
}
break; // Выход из ветвления switch либо из цикла while, do, или for
continue; // Прыжок в конец цикла while, do или for
return x; // Завершает выполнение функции, возвращает значение x
try
{
a;
}
catch (const ExceptionType &ex)
{
b; // Если a; бросает исключение типа ExceptionType, выполнение продолжается здесь
}
catch (...)
{
c; // Если a; бросает какое-либо другое исключение, выполнение продолжается здесь
}
Функции
int sum(int a, int b); // Объявление функции sum, принимающей два параметра int и возвращающей int
void fn(); // fn - это процедура без параметров (псевдо-тип void означает, что возвращаемого значения нет)
void fn(int a = 12); // можно написать fn(), и это будет эквивалентно f(12), т.е. параметр имеет значение по умолчанию
int sum(int a, int b) // Определение функции sum: тело функции станет её реализацией.
{
statements;
}
T operator+(T x, T y) // В выражении вида "a + b", где a, b имеют тип T, вызывается тело функции operator+(a, b)
{
// Реализация оператора...
}
T operator-(T x); // Унарный оператор "минус", вызывается в выражениях вида "-a"
T operator++(); // Префиксная форма оператора a++ или a--
T operator++(int); // Постфиксная форма оператора a++ или a-- (параметр типа int игнорируется)
extern "C" // Все функции, объявленные внутри блока extern "C", не будут подвержены name mangling.
{ // Это полезно, если функции могут быть вызваны из другого языка (например, из C).
void fn();
}
Типы параметров и возвращаемого значения функции могут быть любыми. Функция должна быть либо объявлена (без тела), либо определена (с телом функции) до первого вызова. Можно сначала объявить функцию (и вызвать где-либо), а затем определить (возможно, в другом файле). Каждая программа состоит набора файлов, каждый файл содержит набор глобальных переменных и набор функций. Одна из функций - main - служит точной входа в программу.
int main()
{
statements...
}
int main(int argc, char* argv[])
{
statements...
}
- argv является массивом длины argc, хранящим строки параметров командной строки
- по общему соглашению, main возвращает 0 при успешном выполнении программы, ненулевой код после возникновения ошибки
Функции с различными параметрами могут иметь одинаковое имя (это называется перегрузка функций).
Могут быть перегружены все операторы, кроме “::”, “.”, “.*”, “?:”. Перегрузка не меняет приоритет оператора.
Выражения
Операторы сгруппированы по приоритету, сперва наивысший приоритет. Унарные операторы и присваивание вычисляются справа налево, все остальные слева направо. Во время выполнения программы не происходит проверок на выход за границы массива, на недопустимые указатели и т.п.
T::X // Доступ к символу X, объявленному в классе T
N::X // Доступ к символу X, объявленному в пространстве имён N
::X // Доступ к глобальному имени X (может помочь избежать конфликтов имён)
t.x // Поле или метод объекта t (структуры или класса)
ptr->x // Поле или метод того объекта (структуры или класса), на который указывает ptr
arr[i] // i-й элемент массива arr
fn(x, y) // Вызов функции fn с аргументами x и y
T(x, y) // Конструирование объекта класса T, в конструктор передаются значения x и y
x++ // Увеличивает x на единицу, но возвращает старое значение (постфиксная форма)
x-- // Вычитает единицу из x, но возвращает старое значение (постфиксная форма)
typeid(x) // Вычисляет значение типа std::type_info для объекта x
typeid(T) // Вычисляет (обычно при компиляции) значение типа std::type_info для типа T
dynamic_cast<T>(x) // Приводит x к типу T во время выполнения, выполняет проверку с помощью
// информации о виртуальных методах объекта.
static_cast<T>(x) // Приводит x к типу T без каких-либо проверок
reinterpret_cast<T>(x) // Интерпретирует байты объекта x как байты объекта типа T
const_cast<T>(x) // Конвертирует x к типу T, убирая модификаторы const и volatile
sizeof x // Вычисляет число байт, используемое для хранения объекта x
sizeof(T) // Вычисляет число байт, используемое для хранения типа T
++x // Увеличивает x на единицу, возвращает новое значение (префиксная форма)
--x // Вычитает единицу из x, возвращает новое значение (префиксная форма)
~x // Битовая операция: вычисляет битовое дополнение x
!x // Возвращает true если x имеет значение ЛОЖЬ или 0, иначе false
-x // Унарный минус
+x // Унарный плюс
&x // Вычисление адреса x
*ptr // Доступ к памяти, на которую указывает ptr (т.е. разыменование, *&x эквивалентно x)
new T // Выделяет память для объекта типа T, возвращает его адрес
new T(x, y) // Выделяет память для объекта типа T, в конструктор передаёт x, y, возвращает адрес
new T[n] // Выделяет память для массива из n элементов типа T
delete ptr // Удаляет объект, на который указывает ptr, возвращает системе занятую им память
delete[] ptr // Удаляет массив объектов, на которые указывает ptr
(T) x // Преобразует x к типу T (устаревшая форма, используйте static_cast или в крайнем случае reinterpret_case)
x * y // Умножение
x / y // Деление (для целых чисел происходит отбрасывание дробной части)
x % y // Получение остатка (знак результата совпадает со знаком x)
x + y // Сложение целых чисел либо целочисленного смещения и указателя
// (для указателей эквивалентно выражению &x[y])
x - y // Вычитание целых чисел либо получение смещения от указателя y к указателю x
x << y // Битовая операция: смещение x на y бит влево, эквивалентно x * pow(2, y)
x >> y // Битовая операция: смещение x на y бит вправо, эквивалентно x / pow(2, y)
x < y // ИСТИНА, если x меньше чем y
x <= y // ИСТИНА, если x меньше или равен y
x > y // ИСТИНА, если x больше чем y
x >= y // ИСТИНА, если x больше или равен y
x & y // Битовая операция "И": 3 & 6 равно 2
x ^ y // Битовая операция "ИСКЛЮЧАЮЩЕЕ ИЛИ": 3 ^ 6 равно 5
x | y // Битовая операция "ИЛИ": 3 | 6 равно 7
x && y // Логическое "И": вычисляет x, и если x ЛОЖЬ, возвращает ЛОЖЬ, иначе
// вычисляет y и возвращает его булево значение (ИСТИНА или ЛОЖЬ).
x || y // Логическое "ИЛИ": вычисляет x, и если x ИСТИНА, возвращает ИСТИНА,
// иначе вычисляет y и возвращает его булево значение (ИСТИНА или ЛОЖЬ).
x = y // Присваивает значение y переменной x, возвращает новое значение x
x += y // Эквивалент x = x + y, также существуют -= *= /= <<= >>= &= |= ^=
x ? y : z // Тернарный оператор: возвращает y если x ИСТИНА, иначе z
throw x // Выбрасывает исключение, а если оно не поймано, аварийно завершает программу
x, y // Вычисляет x и y, затем возвращает y (редко используется)
Анонимные функции
Анонимные функции поддерживают замыкание, т.е. захват и удержание внешних переменных.
auto fn1 = [] { // Простая анонимная функция типа `void()`
/* тело функции */;
};
auto fn2 = [] {
};
static_assert(!std::is_same_v(fn1, fn2),
"Две одинаковые с виду лямбды имеют разные типы."
"Каждая лямбда принадлежит уникальному типу данных,"
"имеющему operator().");
int value1 = 10; // Захватим value1 по значению: [value]
int value2 = 10; // Захватим value2 по ссылке: [&value2]
auto fn = [value1, &value2] {
++value1;
++value2;
};
assert(value1 == 10); // Значение не изменилось (изменялась копия)
assert(value2 == 11); // Значение изменилось
auto sum = [](int a, int b) -> int {
return a + b;
};
int x = sum(10, 50); // sum принимает 2 параметра int, возвращает int
int count = 0; // mutable означает, что захваченное
// по значению сохраняется между вызовами
auto bump = [count]() mutable {
++count;
printf("count: %d", count);
};
bump(); // печатает 'count: 1'
bump(); // печатает 'count: 2'
auto sum = [](auto && a, auto && b) {
return a + b; // возвращаемый тип определится автоматически
};
double x = sum(10.2, 40); // sum - обобщённая анонимная функция,
// псевдо-тип auto служит местом
// для параметра любого типа
// Условие в if constexpr вычисляется при компиляции,
// это позволяет в одной обобщённой анонимной функции
// обработать разные типы данных.
auto println = [](auto && value) {
if constexpr (typeid(value) == typeid(int)) {
printf("%d\n", value);
}
if constexpr (typeid(value) == typeid(std::string)) {
printf("%s\n", value.c_str());
}
};
Классы
class T // Новый тип данных T
{
private: // В этой секции символы доступны только для методов класса T
protected: // В этой секции символы доступны ещё для классов-наследников класса T
public: // В этой секции символы доступны для всех желающих
int x; // Поле класса, располагается в памяти как часть объекта класса
void f(); // Метод (функция, являющаяся членом класса)
void g() { return; } // Метод с телом, встроенным в класс
void h() const; // Метод не сможет модифицировать какие-либо поля класса
int operator+(int y); // t + y превращается в вызов метода-оператора t.operator+(y)
int operator-(); // -t превращается в вызов метода-оператора t.operator-()
T(): x(1) {} // Конструктор использует списки инициализации конструктора: ": x(1)"
T(const T& t): x(t.x) {}// Конструктор копирования
T& operator=(const T& t)// Оператор присваивания
{
x = t.x;
return *this;
}
~T(); // Деструктор (автоматически вызываемая процедура очистки)
explicit T(int a); // Позволяет писать t = T(3), но не t = 3
T(float x): T((int)x) {}// Делегирующий конструктор, делегирует инициализацию в T(int)
operator int() const
{return x;} // Оператор преобразования в int, допускает код x = int(t)
static int y; // Поле y становится единственным и глобальным для всех объектов типа T
static void l(); // Метод становится методом класса, доступен для вызова через T::l()
class Z {}; // Вложенный класс T::Z
typedef int Int; // T::Int - синоним типа int
};
void T::fn() // Тело метода fn класса T
{
this->x = x; // this - это адрес текущего объекта (здесь поле x копируется в поле x)
}
int T::y = 2; // Инициализация статической переменной
// (должна быть вне класса для всех типов, кроме целочисленных)
T::l(); // Вызов статического метода (метода класса)
T t; // Создание объекта t типа T с неявным вызовом конструктора T()
t.f(); // Вызов метода f объекта t
struct T { // Эквивалентно коду class T { public:
virtual void i(); // Реализация виртуального метода i может быть перегружена классом-наследником
virtual void g() = 0; // Чисто виртуальный метод, должен быть перезаписан в классе-наследнике
};
class U : public T // Дочерний класс U наследует все поля и методы базового класса T
{
public:
void g(int) override; // Перегрузка метода g
};
Все классы по умолчанию имеют конструктор копирования, оператор присваивания и деструктор, которые рекурсивно вызывают соответствующие методы для базовых классов и полей. Примитивные типы, такие как целые числа, указатели и т.п., копируются прямым копированием памяти, а их деструктор ничего не делает. Конструкторы, операторы присваивания и дееструкторы никогда не копируются. Если у класса не указан ни один конструктор, то у него есть конструктор по умолчанию без аргументов, который лишь вызывает другие конструкторы.
Шаблоны
template <class T> // Функция fn будет перегружена для любых типов-аргументов
T fn(T t);
template <class T>
class X // Класс параметризуется типом T
{
X(T t); // Конструктор принимает значение типа T
};
template <class T>
X<T>::X(T t) // Определение конструктора (метода) за пределами класса
{
}
X<int> x(3); // Тип объекта x - это X<int>, специализация шаблонного класса X
template <class T, class U = T, int n = 0>
class A // Шаблон имеет типы-параметры с типами по умолчанию
{
};
Пространства имён
namespace N {class T {};} // Помещает имя T в пространство имён N
N::T t; // Используем имя T из пространства имён N
using namespace N; // Все символы из пространства имён N теперь доступны без префикса N::
using N::T; // Символ N::T теперь доступен без префикса N::
Отладочный механизм assert
#include <cassert> // Включаем cassert
assert(cond); // Если условие cond не выполняется, распечатать сообщение и аварийно
// завершить программу. В Release-конфигурациях объявлен макрос
// NDEBUG, который превращает assert в пустой макрос. Пустой макрос
// ничего не выполняет и не вычисляет выражение cond.