Лекция 8. Расширение возможностей С++ в новых стандартах языка
Мотивы расширения стандартов языка
Основные новшества, реализованные в новых стандартах языка С++11, С++14, С++17, С++20
Определение типа данных во время компиляции
Определение типа данных во время компиляции
Лямбда-выражения
Лямбда-выражения
Лямбда-выражения
Примеры лямбда-выражений
Кортежи и структурное связывание
Оператор for в форме for each
Оператор for в форме for each
move семантика
Спасибо за внимание!
110.85K

Лекция 8. Расширение возможностей С++ в новых стандартах языка (1)

1. Лекция 8. Расширение возможностей С++ в новых стандартах языка

Виктор Михайлович Гриняк,
профессор
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

2. Мотивы расширения стандартов языка

В 90-х и до середины нулевых годов С++ был самым
распространённым языком в профессиональной разработке
программ общего назначения.
Самый устойчивый вариант языка был зафиксирован стандартом
ANSI C++ (C++99).
В 2000-х годах получили распространение новые типы программ:
кроссплатформенных, мобильных, приложений для браузеров и т.п.
Для их реализации было создано много новых возможностей.
Возникла необходимость их реализации в С++.
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

3. Основные новшества, реализованные в новых стандартах языка С++11, С++14, С++17, С++20

• определение типа данных во время компиляции (auto)
• лямбда-выражения
• кортежи и структурное связывание
• оператор for в форме for each
• семантика перемещения (move семантика)
• много других https://github.com/AnthonyCalandra/modern-cppfeatures
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

4. Определение типа данных во время компиляции

Переменные, тип которых определён как auto, определяют свой тип во
время компиляции по косвенным признакам: типу данных, которым
они инициализируются, типу параметров функции и т.п.
auto an_int = 26; // при компиляции тип данных будет определен как int
auto a_bool = false; // как bool
auto a_float = 26.04f; // как float
auto ptr = &a_float; // как указатель
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

5. Определение типа данных во время компиляции

Тип параметров функции и возвращаемых данных тоже может быть auto.
auto merge(auto a, auto b)
{
std::vector c = do_something(a, b);
return c;
}
std::vector<int> a = { ... }; // какие-то данные
std::vector<int> b = { ... }; // какие-то данные
auto c = merge(a, b);
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

6. Лямбда-выражения

Лямбда-выражения берут начало в функциональной парадигме
программирования, где функция считается объектом и может присваиваться
и передаваться как параметр. Последние стандарты языка С++ дают
возможность использовать некоторые элементы функционального
программирования, что даёт возможность реализации целого ряда удобных
абстракций.
Лямбда-выражения являются безымянными функциональными объектами и
захватывают переменные в различных областях на основе некоторого
краткого синтаксиса.
Лямбда-выражения полезны, если нужно сделать в коде быстрое и
небольшое изменение, без написания для этого отдельной функции. Другое
довольно распространённое использование лямбда выражения –
определение операции сравнения.
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

7. Лямбда-выражения

std::vector< std::pair<int, int> > data = { {1, 3},
{7, 6},
{12, 4} };
std::sort( data.begin(),
data.end(),
[](auto a, auto b) {
return a.second < b.second;
}
);
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

8. Лямбда-выражения

Квадратные скобки определяют область действия лямбда-выражения, задают
полномочия для доступа к локальным переменным.
[ ] - ничего не захватывает. Таким образом, вы не можете использовать любую
локальную переменную внешней области видимости в лямбда-выражении. Вы
можете использовать только параметры.
[=] - захватывает локальные объекты (локальные переменные, параметры) в
области видимости по значению. Вы можете использовать, но не изменять их.
[&] - захватывает локальные объекты (локальные переменные, параметры) в
области видимости по ссылке. Вы можете изменить их, как в примере,
приведённом ниже.
[this] - захватывает этот указатель по значению.
[a, &b] - захватывает объект a по значению, объект b по ссылке.
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

9. Примеры лямбда-выражений

int x = 1;
auto getX = [=] { return x; };
getX(); // == 1
auto addX = [=](int y) { return x + y; };
addX(1); // == 2
auto getXRef = [&]() -> int& { return x; };
getXRef(); // х будет возвращена по ссылке
auto f1 = [&x] { x = 2; }; // OK: x захватывается по ссылке и может изменяться
auto f2 = [x] { x = 2; }; // ОШИБКА, х не может изменяться, так как захвачен по значению
auto f3 = [x]() mutable { x = 2; }; // OK: разрешается изменять захваченные переменные
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

10. Кортежи и структурное связывание

auto user_info = std::make_tuple("M", "Chowdhury", 25); // здесь auto используется,
чтобы уменьшить описание типов
// чтобы получить доступ к данным
std::get<0>(user_info);
std::get<1>(user_info);
std::get<2>(user_info);
Доступ к данным можно получить и так
auto [first_name, last_name, age] = user_info;
Последняя команда [ …. ] называется структурным связыванием.
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

11. Оператор for в форме for each

Синтаксис цикла for в форме for each следующий:
for (объявление_элемента : массив)
{
}
Пример:
int math[] = { 0, 1, 4, 5, 7, 8, 10, 12, 15, 17, 30, 41};
for (int number : math) // итерация по массиву math
{
std::cout << number << ' '; // получаем доступ к элементу массива в этой
// итерации через переменную number
}
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

12. Оператор for в форме for each

Поскольку объявляемый элемент цикла foreach должен быть того же типа, что и элементы
массива, то это идеальный случай для использования ключевого слова auto.
int math[] = { 0, 1, 4, 5, 7, 8, 10, 12, 15, 17, 30, 41};
for (auto number : math) // итерация по массиву math
{
std::cout << number << ' ';
}
Циклы foreach работают не только с фиксированными массивами, но также и с любыми
структурами, для которых задан итератор.
Доступ к элементам можно получить также с помощью ссылки. Это предотвращает
копирование элементов в тех случаях, когда оно не требуется или нежелательно.
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС

13. move семантика

Семантика перемещения (move semantics) - это собирательное название специализированных средств языка
C++, которые предназначены для осуществления перемещения данных (вместо их копирования)
Появление в С++ семантики перемещения требует при разработке сложных классов, работающих с памятью,
помимо определения конструктора копирования, деструктора и копирующего (обычного) оператора
присваивания определять дополнительно конструктор перемещения и перемещающий оператор
присваивания.
class MemoryBlock
{
MemoryBlock(MemoryBlock& other)
{
// конструктор копирования }
MemoryBlock(MemoryBlock&& other)
{
// конструктор перемещения }
};
© В.М. Гриняк, проф. каф. Информационных технологий и систем ВГУЭС
int main()
{
MemoryBlock block;
MemoryBlock copyBlock = block; // Здесь вызовется конструктор
копирования
MemoryBlock moveBlock = std::move(block); // Здесь вызовется
конструктор перемещения
}
English     Русский Правила