Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp/cpp_chapter_0012/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

Как сказал автор C++ Бьерн Страуструп, есть два типа языков программирования: те, которые ругают, и те, которые не используют. C++ — один из популярнейших языков в мире, и конечно же вокруг него много критики. Часть критики вполне обоснована, но часть порождена мифами вокруг языка.

### Мифический язык C/C++
### Мифический язык C/C++ {#block-c-cpp}

C++ появился на свет как надстройка над Си. Долгое время он продолжал быть надмножеством Си. Кроме того, при развитии C++ особый упор делается на обратную совместимость. Если копнуть ещё глубже, то по умолчанию все популярные компиляторы C++ собирают ваш проект таким образом, что к нему подключается стандартная библиотека Си.

Expand Down
2 changes: 1 addition & 1 deletion cpp/cpp_chapter_0022/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ a = 2;
b = ++a; // a=3, b=3
```

Постфиксный оператор возвращает старое значение переменной:
Постфиксный оператор возвращает старое значение переменной: {#block-post-increment}

```cpp
a = 2;
Expand Down
4 changes: 2 additions & 2 deletions cpp/cpp_chapter_0112/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ Function in unnamed namespace

**Header-only** библиотеки состоят _только_ из заголовочных файлов. Их удобно подключать к проекту, ведь дополнительной линковки с такой библиотекой не требуется. Код header-only библиотеки копируется препроцессором в файлы реализации проекта по месту директивы `#include`.

## Рантайм C++
## Рантайм C++ {#block-runtime}

В языках семейства C есть **рантайм** — набор библиотек, реализующих часть описанных в стандарте языка возможностей, его [модель исполнения](https://en.wikipedia.org/wiki/Execution_model) и функции для корректного запуска программы. Рантайм C++ помимо прочего реализует механизм обработки исключений, операторы `new` и `delete` для выделения и освобождения памяти, а также нешаблонный код стандартной библиотеки.

Не путайте концепцию рантайма в C и C++ с рантаймом в [управляемых языках,](https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0_%D1%81%D1%80%D0%B5%D0%B4%D1%8B_%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F) таких как Java, C# и python. В них рантайм — это полноценная среда выполнения программы, укомплектованная сборщиком мусора и виртуальной машиной.

Программы на C++ линкуются не только с рантаймом C++, но и с рантаймом C. Зачем? Дело в том, что рантайм C++ опирается на рантайм C. Например, операторы `new` и `delete` в C++ зачастую реализованы через сишные функции `malloc` и `free`.
Программы на C++ линкуются не только с рантаймом C++, но и с рантаймом C. Зачем? Дело в том, что рантайм C++ опирается на рантайм C. Например, операторы `new` и `delete` в C++ зачастую реализованы через сишные функции `malloc` и `free`. {#block-c-runtime}

С рантаймом можно линковаться динамически и статически. По умолчанию линковка динамическая. С рантаймом можно не линковаться вовсе. Тогда в программе будет доступно минимальное подмножество языка. Это имеет смысл при разработке [встраиваемых систем](https://ru.wikipedia.org/wiki/%D0%92%D1%81%D1%82%D1%80%D0%B0%D0%B8%D0%B2%D0%B0%D0%B5%D0%BC%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0) (embedded systems), драйверов и низкоуровневых программ, запускаемых на устройствах без ОС.

Expand Down
2 changes: 1 addition & 1 deletion cpp/cpp_chapter_0142/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ main.cpp:5:12: error: non-const lvalue reference to type 'basic_string<...>' can
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

## Ссылки на ссылки
## Ссылки на ссылки {#block-reference-collapsing}

У вас [не получится](https://timsong-cpp.github.io/cppwp/n4868/dcl.ref#5) завести ссылку на ссылку. Если вы попытаетесь, то произойдёт [склеивание](https://en.cppreference.com/w/cpp/language/reference.html#Reference_collapsing) или схлопывание ссылок (reference collapsing):

Expand Down
4 changes: 2 additions & 2 deletions cpp/cpp_chapter_0152/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ ptr=0X7FFDA8185ED4

Например, если первый аргумент расположен по адресу `0x7ffce00d8bc0`, а второй — по адресу `0x7ffce00d8bb8`, то функция должна вернуть строку `"0x7ffce00d8bc0 0x7ffce00d8bb8"`. {.task_text}

Для форматирования строки вам понадобится функция [std::format()](https://en.cppreference.com/w/cpp/utility/format/format.html).
Для форматирования строки вам понадобится функция [std::format()](https://en.cppreference.com/w/cpp/utility/format/format.html). {.task_text}

```cpp {.task_source #cpp_chapter_0152_task_0020}
// Ваша реализация check_eq()
Expand Down Expand Up @@ -440,7 +440,7 @@ std::size_t len = p->size(); // вызываем метод строки

Итак, через указатели мы можем работать с объектами классов и структур. А они в свою очередь могут иметь поля с типом «указатель». Если тип такого поля совпадает с типом исходного класса, то перед вами рекурсивная структура данных.

Например, так выглядит структура, реализующая элемент [односвязного списка](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA) целых чисел:
Например, так выглядит структура, реализующая элемент [односвязного списка](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA) целых чисел: {#block-listnode}

```cpp {.example_for_playground .example_for_playground_017}
struct ListNode
Expand Down
17 changes: 17 additions & 0 deletions cpp/cpp_chapter_0153/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,22 @@ std::size_t strlen(const char * str)

Вы можете сравнить своё решение задачи с вариантом, предлагаемом [в разделе cppreference,](https://en.cppreference.com/w/cpp/string/byte/strlen.html) про `std::strlen()`.

## Как соотносятся указатели и итераторы

Указатель — это [составной тип данных](/courses/cpp/chapters/cpp_chapter_0132/) и неотъемлемая часть C++. [Итератор](/courses/cpp/chapters/cpp_chapter_0061/) — это паттерн проектирования для перебора и доступа к элементам некоей коллекции.

В C++ итератором может считаться любой тип, удовлетворяющий нескольким простым требованиям. В частности, он должен поддерживать разыменование через `*`, обращение к члену класса через `->` и инкремент `++`. Все это умеют указатели, поэтому они считаются полноценными итераторами. Более того, они поддерживают перемещение на `n` элементов вперед и назад, а значит, относятся к категории итераторов [произвольного доступа](/courses/cpp/chapters/cpp_chapter_0061/#block-iterator-categories) (random access).

Важный вывод: указатели можно передавать во все алгоритмы стандартной библиотеки, принимающие итераторы!

```cpp
const char s[] = "& pointers & iterators &";

std::println("{}", std::count(s, s + 15, '&'));
```
```
2
```

----------

Expand All @@ -537,3 +553,4 @@ std::size_t strlen(const char * str)
- Вычитание из указателя целого числа уменьшает значение адреса на число, домноженное на размер типа.
- Вычитание из указателя другого указателя имеет смысл, если оба указателя ссылаются на общий участок памяти и имеют одинаковый тип.
- Вычитание одного указателя из другого возвращает количество элементов типа `T` между ними.
- Указатели можно передавать в алгоритмы стандартной библиотеки, принимающие итераторы.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import std;

char normalize(char c)
{
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}

bool is_valid(char c)
{
if (std::isalnum(static_cast<unsigned char>(c)))
return true;

static const std::string allowed_special_symbols = " !@#$%^&*()";

return allowed_special_symbols.find(c) != std::string::npos;
}

bool is_strong(const char * s)
{
return std::strlen(s) > 7;
}

#INJECT-b585472fa

int main()
{
const char * pass = "qwerty";
std::println("checking if password \"qwerty\" is valid... {}", is_valid_pass(pass));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import std;

class Vector
{
public:
Vector() = default;

// Создает вектор из n элементов со значением val
Vector(std::size_t n, int val);

~Vector();

// Возвращает количество элементов
std::size_t size();

// Возвращает емкость - под сколько элементов
// выделена память
std::size_t capacity();

// Возвращает элемент по индексу. Если индекс за
// пределами вектора, кидает исключение
int & at(std::size_t i);

// Возвращает элемент по индексу
int & operator[](std::size_t i);

// Увеличивает емкость вектора: выделяет под него
// память бОльшего размера. Если значение capacity
// меньше текущей емкости, то ничего не делает
void reserve(std::size_t capacity);

// Изменяет реальный размер вектора. Если новый размер
// меньше текущего, удаляет элементы с конца. Если
// больше, то добавляет элементы, инициализированные
// значением по умолчанию. Если размеры равны, то
// ничего не делает
void resize(std::size_t size);

// Добавляет элемент в конец
void push_back(int val);

// Удаляет последний элемент
void pop_back();

private:
// Указатель на сишный массив, в котором
// хранятся элементы
int * m_elements = nullptr;

// Реальное количество элементов
std::size_t m_size = 0;

// Емкость: под сколько элементов выделена память
std::size_t m_capacity = 0;
};

int * make_array(std::size_t n, int val)
{
int * elements{new int[n]};
std::fill(elements, elements + n, val);
return elements;
}

Vector::Vector(std::size_t n, int val):
m_elements{make_array(n, val)},
m_size{n},
m_capacity{n}
{ }

Vector::~Vector()
{
delete[] m_elements;
}

std::size_t Vector::size()
{
return m_size;
}

std::size_t Vector::capacity()
{
return m_capacity;
}

int & Vector::at(std::size_t i)
{
if (i >= m_size)
{
throw std::out_of_range(
std::format("Index {} is out of bounds. Vector size: {}",
i, m_size));
}

return m_elements[i];
}

int & Vector::operator[](std::size_t i)
{
return m_elements[i];
}

void Vector::reserve(std::size_t new_capacity)
{
if (new_capacity <= m_capacity)
return;

int * new_elements = new int[new_capacity];
std::copy(m_elements, m_elements + m_size, new_elements);
std::swap(m_elements, new_elements);
delete[] new_elements;

m_capacity = new_capacity;
}

void Vector::resize(std::size_t size)
{
if (size <= m_size)
{
m_size = size;
return;
}

reserve(size);
std::fill(m_elements, m_elements + size, int{});
}

void Vector::push_back(int val)
{
if (m_size + 1 > m_capacity)
reserve(std::max(m_capacity, 1uz) * 2);

m_elements[m_size++] = val;
}

int main()
{
#INJECT-b585472fa
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <cstdlib> // Вместо stdlib.h

import std;

int main()
{
const std::size_t n = 5;
const std::size_t bytes = n * sizeof(int);

// Обращаемся к malloc из пространства имен std
int * arr = static_cast<int *>(std::malloc(bytes));

// Проверка, чтобы при обращении к памяти не получить UB
if (arr == nullptr)
{
std::println("Couldn't allocate {} bytes for array", bytes);
return 1;
}

for (int i = 0; i < n; ++i)
{
arr[i] = i * i;
std::println("{}-th element. Value: {}", i, arr[i]);
}

// Обращаемся к free из пространства имен std
std::free(arr);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import std;

int main()
{
#INJECT-b585472fa
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import std;

#INJECT-b585472fa

int main()
{
SemVer * ver = new SemVer{1, 0, 134};
ver->print();
delete ver;
std::println("Exiting main");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import std;

class SemVer
{
public:
SemVer()
{
std::println("Default constructor");
}

SemVer(std::int32_t major, std::int32_t minor, std::int32_t patch)
: m_major(major), m_minor(minor), m_patch(patch)
{
std::println("Parameterized constructor: {}.{}.{}", m_major, m_minor, m_patch);
}

~SemVer()
{
std::println("Destructor: {}.{}.{}", m_major, m_minor, m_patch);
}

void print()
{
std::println("Version: {}.{}.{}", m_major, m_minor, m_patch);
}

private:
std::int32_t m_major = 0;
std::int32_t m_minor = 0;
std::int32_t m_patch = 0;
};


#INJECT-b585472fa
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import std;

class SemVer
{
public:
SemVer()
{
std::println("Default constructor");
}

SemVer(std::int32_t major, std::int32_t minor, std::int32_t patch)
: m_major(major), m_minor(minor), m_patch(patch)
{
std::println("Parameterized constructor: {}.{}.{}", m_major, m_minor, m_patch);
}

~SemVer()
{
std::println("Destructor: {}.{}.{}", m_major, m_minor, m_patch);
}

void print()
{
std::println("Version: {}.{}.{}", m_major, m_minor, m_patch);
}

private:
std::int32_t m_major = 0;
std::int32_t m_minor = 0;
std::int32_t m_patch = 0;
};


#INJECT-b585472fa
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import std;

#INJECT-b585472fa

int main()
{
process_and_release();
}
Loading