
- •Тема 1: Динамическая память и интеллектуальные указатели
- •1. Особенности использования динамической памяти (распределяемая память, heap, freestore), стека. Примеры использования.
- •2. Особенности выделения и освобождения памяти для автоматических глобальных и локальных объектов, статических глобальных и локальных объектов. Примеры использования.
- •3. Операторы new и delete при работе с динамической памятью. Свойства указателей, передаваемых оператору delete. Примеры использования.
- •4. Утечка памяти (memory leak). Потерянный указатель (dangling pointer, wild pointer). Примеры использования.
- •5. Проблемы, связанных с использованием операторов new и delete при управлении динамической памятью. Примеры использования.
- •6. Динамически создаваемые объекты (dynamically allocated objects). Интеллектуальные указатели (smart pointers): преимущества, недостатки, особенности использования, различия. Примеры использования.
- •8. Класс интеллектуального указателя shared_ptr. Методы класса указателя shared_ptr. Особенности и примеры использования.
- •9. Копирование и присваивание указателей shared_ptr. Примеры использования.
- •10. Создание и использование объектов интеллектуальных указателей. Примеры.
- •11. Функция make_shared(). Использование функции make_shared() для создания и инициализации объектов интеллектуальных указателей. Примеры использования.
- •12. Счетчик ссылок (reference count), счетчик слабых ссылок (weak count), функция-удалитель (deleter), выделитель памяти (allocator). Примеры использования.
- •13. Использование ключевого слова auto. Примеры использования.
- •14. Классы, ресурсы которых имеют динамическую продолжительность существования. Случаи их использования. Совместное использование данных двумя объектами. Примеры использования.
- •15. Использование оператора new для динамического резервирования памяти и инициализации объектов. Примеры использования.
- •17. Особенности создание пользовательского класса умного указателя (smart pointer). Перечень необходимых условий для реализации пользовательского класса умного указателя. Пример использования.
- •18. Особенности копирования, присваивания и удаления объектов при создании пользовательского класса умного указателя (smart pointer). Пример использования.
- •19. Размещающий оператор new (placement new). Передача ему объекта nothrow. Пример использования.
- •20. Особенности исчерпания памяти. Исключения, возникающие при исчерпании памяти. Пример использования.
- •21. Время жизни динамически создаваемых объектов. Примеры использования.
- •22. Присваивание указателю значения nullptr. Примеры использования.
- •23. Использование указателя shared_ptr совместно с оператором new. Примеры использования.
- •24. Особенности совместного использования обычных указателей и интеллектуальных. Примеры использования.
- •30. Передача в функцию и возврат из функции указателя типа unique_ptr. Примеры использования.
- •31. Использование класса auto_ptr. Особенности и пример использования.
- •32. Передача функции удаления указателю unique_ptr. Примеры использования.
- •33. Класс интеллектуального указателя weak_ptr. Методы класса указателя weak_ptr. Особенности и пример использования.
- •34. Динамические массивы. Особенности работы с динамическими массивами. Особенности резервирования памяти для массивов. Динамическое резервирование пустого массива. Примеры использования
- •35. Оператор new и динамические массивы. Класс bad_array_new_length. Примеры использования.
- •36. Инициализация массива динамически созданных объектов встроенных и пользовательских типов. Примеры использования.
- •37. Особенности освобождение памяти, выделенной для динамических массивов. Примеры использования.
- •38. Взаимодействие интеллектуальных указателей (класс unique_ptr) и динамических массивов. Примеры использования.
- •39. Класс Allocator и специальные алгоритмы. Примеры использования.
- •40. Алгоритмы копирования и заполнения неинициализированной памяти. Примеры использования
- •1. Особенности обработки исключительных ситуаций с использованием функции abort() и exit(). Преимущества и недостатки. Примеры использования.
- •2. Особенности обработки исключительных ситуаций с помощью возврата кода ошибки. Преимущества и недостатки. Примеры использования.
- •4. Роль типа исключения в его обработке. Охранный блок, блок перехвата. Использование механизма обработки исключений. Примеры использования.
- •5. Использование объектов классов в качестве исключений. Одинаковые свойства и различия операторов throw и return. Примеры использования.
- •7. Алгоритм раскручивания стека. Раскручивание стека при нормальном и аварийном завершении программы. Пример использования.
- •8. Понятие абсолютного обработчика, его синтаксис, особенности использования. Пример использования.
- •9. Класс exception. Методы класса exception. Использование наследования класса exception. Пример использования.
- •11. Исключение bad_alloc и операция new. Примеры использования. Использование нулевого указателя и операции new. Примеры использования.
- •12. Использование исключений вместе с классами и наследованием. Особенности использования вложенных классов.
- •13. Потеря исключений. Неперехваченное исключение. Использование функций terminate() и set_terminate().
- •14. Непредвиденное исключение. Использование функций unexpected() и set_unexpected(). Исключение типа std::bad_exception.
- •15. Предостережения относительно использования исключений. Использование и управление исключениями в современных языках программирования.
- •4. Изменение основания системы счисления, используемого для отображения данных. Набор констант типа fmtflags (константы форматирования), решаемые ими задачи.
- •7. Istream как псевдоним шаблона класса basic_istream. Взаимосвязь основных классов ввода/вывода. Ввод данных с помощью объекта cin
- •Istream и ostream как специализации для специализаций char. Wistream и wostream как специализации для типа wchar_t.
- •10. Класс basic_iostream. Iostream как псевдоним шаблона класса basic_iostream. Взаимосвязь основных классов ввода/вывода
- •12. Объекты wcout, wcin, wclog, wcerr, cout, cin, clog, cerr. Особенности их создания и использования.
- •14. Заголовочный файл iomanip. Функции setprecision(), setfill(), setw(). Использование манипуляторов из файла iomanip.
- •Тема 4: Файловый ввод-вывод
- •Понятие файла. Бинарные и текстовые файлы. Преимущества, недостатки, особенности использования.
- •Аргументы командной строки (argc, argv). Обработка данных командной строки. Примеры их использования.
- •Проверка состояния файлового потока. Метод is_open(). Особенности открытия нескольких файлов. Пример их использования.
- •Константы типа seekdir: ios_base::beg, ios_base::cur, ios_base::end. Примеры их использования.
- •Особенности работы с временными файлами. Функция tmpnam_s(). Пример её использования.
- •Класс string. Внутреннее форматирование с использованием классов ostringstream, istringstream. Примеры их использования.
- •Тема 5: Стандартная библиотека шаблонов stl.
- •1. Базовые принципы библиотеки шаблонов stl. Использование библиотеки stl. Заголовочные файлы complex, random.
- •4. Иерархия и концепция итераторов. Необходимость использования каждого типа итераторов. Указатель как итератор. Применение алгоритмов stl к контейнерам, не относящимся к библиотеке stl.
- •5. Входные, выходные, однонаправленные, двунаправленные итераторы, итераторы произвольного доступа: понятие, требования, особенности использования, направленность.
- •6. Шаблонный класс vector, deque, stack. Особенности, методы, принципы работы, возможности
- •7. Шаблонный класс array, valarray. Особенности, методы, принципы работы, возможности
- •8. Шаблонный класс list, forward_list. Особенности, методы, принципы работы, возможности
- •9. Шаблонный класс queue, priority_queue. Особенности, методы, принципы работы, возможности
- •10. Шаблонные классы set и multiset. Особенности, методы, принципы работы, возможности
- •11. Шаблонные классы map и multimap. Особенности, методы, принципы работы, возможности
- •12. Понятие функциональных объектов (функторов). Концепции функторов: генератор, унарная функция, бинарная функция, предикат, бинарный предикат. Предопределенные функторы
- •14. Группы алгоритмов. Алгоритмы «по месту», копирующие алгоритмы. Сравнение функций stl и методов контейнеров stl
- •15. Математические операции и их эквиваленты-функторы. Понятие полного упорядочения и квазиупорядочения
- •17. Понятие обобщенного программирования. Связь обобщенного программирования и библиотеки stl.
- •18. Использование алгоритма copy(), классов ostream_iterator и istream_iterator в качестве моделей входных и входных итераторов
- •19. Итераторы специального назначения: reverse_iterator, back_insert_iterator, front_insert_iterator, insert_iterator
- •Тема 6: Обзор Java. Введение в ооп в Java.
- •2. Обзор и отличительные особенности языка Java. Программная платформа и виртуальная машина Java. Особенности разработки и исполнения объектно-ориентированных приложений на Java.
- •3. Сборка мусора в Java. Пакет jdk: особенности, содержимое, необходимость использования, версии. Ide для работы на Java.
- •4. Особенности настройки работы платформы Java и запуск приложения на языке Java без ide.
- •5. Особенности лексики Java: литералы, идентификаторы, разделители, комментарии, ключевые слова.
- •6. Примитивные типы данных Java. Типизация. Целые числа (byte, short, int, long), числа с плавающей точкой (float, double), символы.
- •7. Переменные. Объявление переменной. Преобразование и приведение типов. Автоматическое приведение и продвижение типов в выражениях. Логические выражения. Область и срок действия переменной.
- •8. Операции (арифметические, поразрядные, отношения, логические (укороченные, обычные)). Операция присваивания. Предшествование операций.
- •9. Управляющие операторы (выбора, цикла, перехода). Разновидность цикла for в стиле for each. Комментарии в Java. Оператор instanceof.
- •Принципы объектно-ориентированного программирования в Java.
11. Исключение bad_alloc и операция new. Примеры использования. Использование нулевого указателя и операции new. Примеры использования.
В настоящее время в C++ проблемы, возникающие во время выделения памяти с помощью операции new, обрабатываются путем генерации в операторе new исключения типа bad_alloc. Заголовочный файл new включает объявление класса bad_alloc, открыто унаследованного от класса exception.
В более ранних версиях стандарта С++ операция new возвращала нулевой указатель, если не могла выделить запрошенный объем памяти.
Текущий подход демонстрируется в программе ниже. Если исключение перехвачено, то программа выводит зависящее от реализации сообщение, которое возвращается унаследованным методом what(), и затем завершается.
//Пример №10. Обработка исключения типа bad_alloc
#include <iostream>
#include <new>
#include <cstdlib>//для exit(), EXIT_FAILURE using namespace std; struct Company { double data[20000];
};
int Ex10() {
Company* company; try {
cout << "Попытка выделения большого блока памяти:\n"; //Попытка выделения большого блока памяти company = new Company[10000];//1 600 000 000 байт cout << "Возможно выполнение следующего запроса:
\n";//вывод результатов запроса new
}
catch (bad_alloc& ba) {
cout<<"Словлено исключение выделения
памяти!\n";//произошло исключение
cout << ba.what() << endl;
exit(EXIT_FAILURE);
}
cout << "Память успешно выделена\n"; company[0].data[0] = 4; cout << company[0].data[0] << endl; delete[] company;
return 0;
}
В этом случае метод what() возвращает строку "std::bad_alloc".
Если программа выполнилась без ошибок, можно попробовать увеличить объем запрашиваемой памяти.
НУЛЕВОЙ УКАЗАТЕЛЬ И ОПЕРАЦИЯ NEW
К этому моменту уже написан большой объем кода, когда старая реализация оператора new возвращала в случае сбоя нулевой указатель. В некоторых компиляторах предусмотрен флаг, который позволяет пользователю выбрать удобное для них поведение операции new. В текущем стандарте языка имеется альтернативный вариант new, который по-прежнему возвращает нулевой указатель. Он используется примерно так:
int* ptrInt = new (std::nothrow) int;
int* ptrIntArr = new (std::nothrow) int[500];
Эта форма позволяет переписать основную часть кода следующим образом:
Company* company;
company = new (std::nothrow) Company[10000];//1 600 000 000 байт if (company == 0){
cout << "Невозможно выделить память!\n"; exit(EXIT_FAILURE);
}
12. Использование исключений вместе с классами и наследованием. Особенности использования вложенных классов.
Исключения, классы и наследование взаимодействуют несколькими способами. Во-первых, можно породить один класс исключения от другого класса, как это сделано в стандартной библиотеке C++. Во-вторых, можно добавить исключения в классы, добавив объявление класса исключения в определение класса. В-третьих, такое вложенное объявление может быть унаследовано и само служить базовым классом.
Код в примере ниже предназначен для исследования таких возможностей. В этом заголовочном файле объявлен простой класс Sales, содержащий значение года, и массив из 12 ежемесячных объемов продаж.
Класс LabeledSales порожден от класса Sales и содержит дополнительный элемент для хранения метки данных.
//Пример №11. Использование исключений и наследования
//файл Sales.h
#pragma once
#include <iostream>
#include <exception>
#include <stdexcept> #include <string> using namespace std; class Sales { protected:
enum { MONTHS = 12 };//может быть статической константой public: class BadIndex : public std::logic_error { private: int badIndex; //недопустимое значение индекса public:
explicit BadIndex(int ix, const std::string& s =
"Ошибка индекса в объекте класса Sales\n"); int badIndexValue() const { return badIndex; } virtual ~BadIndex() noexcept {}
};
explicit Sales(int yy = 0);
Sales(int year, const double* gross, int n); virtual ~Sales() { } int Year() const { return year; } virtual double operator [] (int i) const; virtual double& operator [] (int i); private:
double gross[MONTHS]; int year;
};
class LabeledSales : public Sales { public: class BadIndexLabeled : public Sales::BadIndex { private:
std::string lbl; public:
BadIndexLabeled(const std::string& lb, int ix, const std::string& s = "Ошибка индекса в объекте класса
LabeledSales\n");
const std::string& label_val() const { return lbl; } virtual ~BadIndexLabeled() noexcept() {}
};
explicit LabeledSales(const std::string& lb = "none", int yy = 0);
LabeledSales(const std::string& lb, int yy, const double* gr, int n);
virtual ~LabeledSales() { }
const std::string& Label() const { return label; } virtual double operator[] (int i) const; virtual double& operator[] (int i); private:
std::string label;
};
//Файл sales.ерр #include "sales.h" using std::string;
Sales::BadIndex::BadIndex(int ix, const string& s) : std::logic_error(s), badIndex(ix) {}
Sales::Sales(int year) { this->year = year; for (int i = 0; i < MONTHS; ++i) gross[i] = 0;
}
Sales::Sales(int year, const double* gross, int n) { this->year = year;
int lim = (n < MONTHS) ? n : MONTHS;
int i;
for (i = 0; i < lim; ++i) this->gross[i] = gross[i]; //Для i > n и і < MONTHS for (; i < MONTHS; ++i)
this->gross[i] = 0;
}
double Sales::operator[] (int i) const{ if (i < 0 || i >= MONTHS) throw BadIndex(i);
return gross[i];
}
double& Sales::operator[] (int i){ if (i < 0 || i >= MONTHS) throw BadIndex(i); return gross[i];
}
LabeledSales::BadIndexLabeled::BadIndexLabeled(const string& lb, int ix,const string& s) : Sales::BadIndex(ix, s){
lbl = lb;
}
LabeledSales::LabeledSales(const string& lb, int yy): Sales(yy){ label = lb;
}
LabeledSales::LabeledSales(const string& lb, int yy,const double* gr, int n): Sales(yy, gr, n){ label = lb;
}
double LabeledSales::operator[] (int i) const{
if (i < 0 || i >= MONTHS) throw BadIndexLabeled(Label(), i); return Sales::operator[](i);
}
double& LabeledSales::operator[] (int i){ if (i < 0 || i >= MONTHS) throw BadIndexLabeled(Label(), i); return Sales::operator [] (i);
}
Символьная константа MONTHS расположена в защищенном разделе Sales, поэтому ее значение доступно для производных классов, таких как LabeledSales.
Класс bad_index находится в открытом разделе Sales; это делает его доступным в качестве типа для клиентских блоков catch. Правда, вовне этот тип нужно указывать как Sales::bad_index. Данный класс порожден от стандартного класса logic_error, он может сохранять недопустимые значения индексов и сообщать о них.
Класс nbad_index находится в открытом разделе LabeledSales и доступен в клиентском коде как LabeledSales::nbad_index.
Он порожден от bad_index и может дополнительно сохранять и выводить метки объектов LabeledSales. Поскольку класс bad_index порожден от logic_error, то и nbad_index также порожден от logic_error.
Оба класса содержат перегруженные методы operator [], которые предназначены для доступа к хранимым в объекте отдельным элементам массива и для генерации исключения, если индекс массива выходит за допустимые пределы.
Оба класса, bad_index и nbad_index, используют спецификацию исключения throw(). Причина в том, что оба они, в конечном счете, унаследованы от базового класса exception, виртуальный деструктор которого использует спецификацию исключения. Это характерно для С++98; в С++11 деструктор exception не имеет спецификации исключения.
В примере также показана реализация методов, которые не были встроенным образом определены в классе. Обратите внимание, что вложенные классы требуют многократного использования операции разрешения контекста. Учтите также, что функции operator [] генерируют исключения при выходе индекса за пределы массива.
Рассмотрим пример использования этих классов в программе, которая сначала пытается выйти за пределы массива в объекте LabeledSales по имени sales2, а затем — за пределы массива в объекте Sales по имени sales1. Эти попытки реализованы в двух разных блоках try, которые проверяют каждый вид исключений.
Вложенные исключения направлены на решение проблемы путем присоединения исключения низкого уровня, которое описывает причину, к исключению высокого уровня, которое описывает, что это означает в данном конкретном случае.
//Пример №12. Использование вложенных классов исключений
#include <iostream> #include "sales.h" int main() { system("chcp 1251"); system("cls"); using std::cout; using std::cin; using std::endl; double valsl[12] = {
1220, 1100, 1122, 2212, 1232, 2334, 2884, 2393, 3302, 2922, 3002, 3544 };
double vals2[12] = {
12, 11, 22, 21, 32, 34,
28, 29, 33, 29, 32, 35 };
Sales salesl(2011, valsl, 12);
LabeledSales sales2("Компания №1", 2012, vals2, 12);
cout << "Первый блок try: \n";//первый блок try
try {
int i;
cout << "Год = " << salesl.Year() << endl;
for (i = 0; i < 12; ++i) {
cout << salesl[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "Год = " << sales2.Year() << endl; cout << "Метка = " << sales2.Label() << endl;
for (i = 0; i <= 12; ++i) {
cout << sales2[i] << ' ';
if (i % 6 == 5)
cout << endl;
}
cout << "Конец первого блока try.\n";
}
catch (LabeledSales::BadIndexLabeled & bad) {
cout << bad.what();
cout << "Компания: " << bad.label_val() << endl;//компания
cout << "Неверный индекс: " << bad.badIndexValue() << endl;//недопустимый индекс
}
catch (Sales::BadIndex & bad) { cout << bad.what();
cout << "Неверный индекс: " << bad.badIndexValue() << endl;//недопустимый индекс
}
cout << "\nСледующий блок try: \n";//второй блок try
try {
sales2[2] = 37.5;
salesl[20] = 23345;
cout << "Конец второго блока try.\n";//конец второго блока try
}
catch (LabeledSales::BadIndexLabeled & bad) {
cout << bad.what();
cout << "Компания: " << bad.label_val() << endl;//компания
cout << "Неверный индекс: " << bad.badIndexValue() << endl;//недопустимый индекс
}
catch (Sales::BadIndex & bad) { cout << bad.what();
cout << "Неверный индекс: " << bad.badIndexValue() << endl;//недопустимый индекс
}
cout << "Программа выполнена\n";
return 0;
}