Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Question 3
- Const correctness
- Это означает использование ключевого слова const для предотвращения мутации объектов const.
- В случаях pass by reference-to-const и pass by pointer-to-const любые попытки изменить строку std::вызывающего объекта в функциях f() будут помечены компилятором как ошибка во время компиляции. Эта проверка выполняется во время компиляции: нет пространства или времени выполнения скорость затрат по строительству. В случае pass by value (f3 ()) вызываемая функция получает копию строки std:: вызывающего объекта. Это означает, что f3() может изменить свою локальную копию, но копия будет уничтожена, когда f3 () вернется. В частности, f3 () не может изменить объект std::string вызывающего объекта.
- В качестве противоположного примера предположим, что вы хотите создать функцию g (), которая принимает std::string, но вы хотите, чтобы вызывающие знали, что g () может изменить объект std::string вызывающего объекта. В этом случае g () может получить свой параметр std:: string…
- Объявление постоянства параметра - это просто еще одна форма безопасности типов.
- Если вы обнаружите, что безопасность обычного типа помогает вам корректировать системы (это действительно так; особенно в больших системах), вы также найдете, что помогает корректность const.
- Преимущество корректности const состоит в том, что она предотвращает непреднамеренное изменение того, что вы не ожидали, что будет изменено. В конечном итоге вам нужно украсить свой код несколькими дополнительными нажатиями клавиш (ключевое слово const), с тем преимуществом, что вы сообщаете компилятору и другим программистам некоторую дополнительную важную семантическую информацию — информацию, которую компилятор использует для предотвращения ошибок, а другие программисты используют в качестве документации.
- Это означает, что p указывает на объект класса X, но p не может быть использован для изменения этого объекта X (Естественно, p также может быть NULL).
- Прочитайте его справа налево: "p-это указатель на X, который является постоянным.”
- В чем разница между “const X* p”, “X* const p” и “const X* const p”?
- Прочитайте объявления указателя справа налево.
- const X* p означает "p указывает на X, который является const": объект X не может быть изменен через p.
- X * const p означает " p-это указатель const на X, который не является const”: вы не можете изменить сам указатель p, но вы можете изменить объект X через p.
- константный х* const и Р означает “P-это константный указатель на X, который является константой”: вы не можете изменить указатель п себя, и вы не можете изменить объект X через Р.
- Что означает "const X& x"?
- Это означает, что x псевдонимы объекта X, но вы не можете изменить этот объект X через x.
- Прочитайте его справа налево “ " x-это ссылка на X, который является const.”
- Например, если класс X имеет функцию-член const, такую как inspect () const, можно сказать x. inspect (). Но если класс X имеет неконстантную функцию-член под названием mutate (), то будет ошибкой, если вы скажете x.mutate ().
- class Fred {
- public:
- void inspect() const; // This member promises NOT to change *this
- void mutate(); // This member function might change *this
- };
- void userCode(Fred& changeable, const Fred& unchangeable)
- {
- changeable.inspect(); // Okay: doesn't change a changeable object
- changeable.mutate(); // Okay: changes a changeable object
- unchangeable.inspect(); // Okay: doesn't change an unchangeable object
- unchangeable.mutate(); // ERROR: attempt to change unchangeable object
- }
- Константная ссылка
- Обычная ссылка - равна чему-то
- int a;
- int& ar = a;
- ar = 5;//поменяется зачение а
- а = 9;
- ar = b;//ничего не сделается
- int a;
- const int& ar = a;
- ar = 5;//ошибка, константная
- Константная ссылка - это нонсенс. Она по определению константная. Компилятор скорее всего выдаст предупреждение, что он проигнорировал const.
- int& const x; //не имеет смысла
- Константный указатель
- Константный указатель — это указатель, значение которого не может быть изменено после инициализации. Для объявления константного указателя используется ключевое слово const между звёздочкой и именем указателя:
- int value = 7;
- int *const ptr = &value;
- Подобно обычным константным переменным, константный указатель должен быть инициализирован значением при объявлении. Это означает, что он всегда будет указывать на один и тот же адрес. В примере выше ptr всегда будет указывать на адрес value
- Но так как value - const, то ее значение может измениться через разыменовывание константного указателя:
- int value = 7;
- const int *const ptr = &value;//константный указатель на константное значение, его нельзя перенаправить на другое значение, нельзя поменять значение того, на что он указывает
- const int* ptr = &a; // указатель на константу
- ptr = &b; // ok
- ++(*ptr); // error: read-only variable is not assignable
- int* const cptr = &a; // константный указатель
- cptr = &b; // error: expression is not assignable
- ++(*cptr); // ok
- const int* const cc = &a; // константный
- // указатель на константу
- Константный методы
- Константный метод — это метод, который гарантирует, что не будет изменять объект или вызывать неконстантные методы класса (поскольку они могут изменить объект).
- Чтобы сделать getValue() константным, нужно просто добавить ключевое слово const к прототипу функции после списка параметров, но перед телом функции:
- int getValue() const { return m_value; }
- Для методов, определённых вне тела класса, ключевое слово const должно использоваться как в прототипе функции в теле класса, так и в определении функции.
- Обратите внимание, конструкторы не могут быть константными. Это связано с тем, что они должны иметь возможность инициализировать переменные-члены класса, а константный конструктор этого не может сделать. Следовательно, в С++ константные конструкторы запрещены.
- Константные переменные
- В языке C++ появился ещё один способ — использование константных переменных, то есть переменных, которые нельзя изменять после инициализации. Рассмотрим на том же примере:
- const double PI=3.14; // здесь PI — константная переменная
- #define PI 3.14
- Константные замыкания ТУТ ПРО ОБЫЧНЫЕ
- лямбда– — это удобный способ определения объекта анонимной функции ( замыкания) непосредственно в расположении, где оно вызывается или передается в качестве аргумента функции. Обычно лямбда-выражения используются для инкапсуляции нескольких строк кода, передаваемых алгоритмам или асинхронным методам.
- Лямбда-выражение начинается с предложения Capture (лямбда- знаком в стандартном синтаксисе), который указывает, какие переменные захватываются и является ли захват значением или ссылкой. Доступ к переменным с префиксом с амперсандом (&) осуществляется по ссылке, а к переменным без префикса — по значению.
- Пустое предложение фиксации ([ ]) показывает, что тело лямбда-выражения не осуществляет доступ к переменным во внешней области видимости.
- Mutable
- Бывают случаи, когда строгое придерживание константности неудобно. Объект может оставаться логически константным ("logically const"), но при этом его физическая константность ("physically const") может быть нарушена.
- mutable означает, что спецификатор const, примененный к классу, следует игнорировать. По стандарту
- только данные класса могут быть mutable.
- Признак правильного использования mutable: если при доступе к данным через интерфейс класса все выглядит так, будто в классе ничего не менялось, то можно использовать mutable.
- Ключевое слово mutable существует в стандарте языка С++ именно для решения данного класса проблем. Его можно добавить к переменным членам класса для указания того, что данная переменная может изменяться даже в константном контексте.
- Есть и ещё один вариант применения ключевого слова mutable и он связан с сохранением состояния в лямбда-функциях. Обычно оператор вызова функции замыкания является константным. Другими словами — лямбда не может модифицировать переменные, захваченные по значению:
- о ключевое слово mutable может быть применено ко всей лямбда-функции, что сделает все её переменные изменяемыми:
- Стандартная библиотека C++
- STD
- По правилам языка C++ соответствующий компонент STD добавляется в программу путем включения заголовочного файла с помощью директивы:a
- #include <имя_файла>
- Основные компоненты STD:
- Language support library (языковая поддержка)
- Diagnostics library (исключения)
- General utilities library (утилиты)
- Strings library (строки)
- Localization library (локализация)
- Containers library (контейнеры)
- Iterators library (итераторы)
- Algorithms library (алгоритмы)
- Numerics library (числа)
- Input/output library (ввод/вывод)
- Regular expressions library (регулярные выражения)
- Atomic operations library (атомарные операции)
- Thread support library (многопоточность)
- STL состоит из двух основных частей: классы контейнеров и алгоритмы для работы с элементами контейнеров. Все компоненты STL являются шаблонами, поэтому их можно использовать для произвольных типов элементов, включая абстрактные.
- В STL выделяют пять основных компонентов:
- контейнер (container): управляет набором объектов в памяти.
- итератор (iterator): обеспечивает для алгоритма средство доступа к содержимому контейнера.
- алгоритм (algorithm): определяет вычислительную процедуру.
- функциональный объект (function object): инкапсулирует функцию в объекте для использования другими компонентами.
- адаптер (adaptor): адаптирует компонент для обеспечения различного интерфейса.
- Ввод-вывод.
- #include <iostream>
- Библиотека iostream определяет три стандартных потока:
- cin стандартный входной поток
- cout стандартный выходной поток
- cerr стандартный поток вывода сообщений об ошибках
- Для ввода текста до символа перевода строки используется манипулятор потока getline():
- cin.getline(s, 80);
- endl Помещение в выходной поток символа конца строки '\n'
- get() Ожидает ввода символа
- getline(указатель, количество) Ожидает ввода строки символов. Максимальное количество символов ограничено полем количество
- Контейнеры
- последовательные контейнеры — вектор (vector), двусвязный список (list), дэк (deque);
- ассоциативные контейнеры — множества (set и multiset ), хэш-таблицы (map и multimap);
- псевдо контейнеры — битовые маски (bitset), строки (string и wstring), массивы (valarray);
- ВЕКТОР
- размер вектора может динамически изменяться в любое время операциями добавления (метод push_back()) или удалении (например, метод pop_back()) элемента. Так же, как и для массива, мы можем обратиться к произвольному элементу вектора операцией индексации [ n ].
- Сет
- set<type_here> set_name_here;
- Set/map - красно-черное дерево
- Добавление/удаление элемента - O(logn)
- Поиск элемента - O(logn)
- Хранятся в порядке сортировки
- Set - множество уникальных элементов.
- #include <set>
- lower_bound - первый элемент, не меньше X
- upper_bound - первый элемент, больше X
- Мэп
- map - контейнер с ключами и значениями
- #include <map>
- std::map<std::string, int> a({
- {"aba", 2},
- {"aac", 17},
- {"za", 1},
- });
- MULTIMAP
- Содержит упорядоченные пары <ключ,значение>, где ключ и значение могут принадлежать к произвольным типам;
- Элементы с любыми значениями ключа не должны быть уникальными, в упорядоченной последовательности элементов (по ключу) такие эквивалентные элементы представлены, как разные элементы, и располагаются они друг за другом;
- Поскольку ключи могут совпадать, то операция добавления новой пары в таблицу (метод insert()) всегда успешна. Поэтому нет смысла возвращать результат такой операции: возвращаемое значение — void;
- Поскольку теперь в контейнере может находиться много элементов с равными ключами, то вводится дополнительный метод count(). Он получает параметром значение ключа, возвращает число вхождений элементов, имеющих такой ключ, в контейнер;
- Операции удаления (метод erase()) с указанием ключа удаляемого элемента удаляет все сразу элементы с совпадающими ключами;
- MULTISET
- multiset — это контейнер, который также будет содержать элементы в отсортированном порядке при добавлении, но он хранит повторяющееся элементы, по сравнению с множеством set. Часто его называют мультимножество.
- INITIALIZER LIST
- std::vector<int> a({1, 2, 2, 5});
- // {..} - список инициализации
- // можно создать его явно
- std::initializer_list<int> b{1, 2, 3};
- // Потом от него можно создать какой-нибудь контейнер
- std::vector<int> c(b);
- // Больше он ничего не умеет :)
- UNORDEREDMAP/SET
- #include <unordered_set>
- #include <unordered_map>
- unordered_set/unordered_map - хеш-таблица
- Добавление/удаление элемента - O(1)
- Поиск элемента - O(1)
- Unordered структуры умеют почти то же самое, что и set/map
- LIST
- Что такое list в STL? Это такой контейнер (хранилище элементов одинакового типа), который представляет собой двусвязный список. Двусвязный список являет собой сущность, где каждый отдельный внутренний элемент имеет прямую связь со своими соседствующими элементами, при этом любые не соседствующие элементы друг с другом никаких связей не имеют и ничего друг о друге не знают.
- В отличие от других контейнеров для типа list не определена операция обращения по индексу или функция at(), которая выполняет похожую задачу.
- std::list<int> l({1, 2, 3, 4, 5});
- l.pop_back();
- l.pop_front();
- l.push_back(17);
- l.push_front(7);
- Stl containers: queue, stack, deque
- #include <stack>
- #include <queue>
- queue - добавление в конец, удаление из начала за O(1)
- stack - добавление в конец, удаление с конца за O(1)
- deque - добавление/удаление в конец, добавление/удаление в
- начало, random access доступ за O(1)
- #include <priority_queue>
- priority_queue - куча
- Добавление за O(logn)
- Получить максимум/минимум за O(1)
- ТИПЫ ИТЕРАТОРОВ
- Рэндом аксес и обычный
- Рэндом у тех контейнеров, у которых есть []
- Рандом+5-5, форвард только вперед и все
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement