- •1. Понятие класса. Методы класса. Управление доступом к компонентам.
- •2. Объявление и определение класса. Внешнее определение функций.
- •3. Создание, копирование и удаление объекта.
- •4. Статические компоненты класса. Инициализация статических компонентов класса.
- •5. Наследование. Типы наследования. Виртуальное наследование.
- •6. Виртуальные функции
- •7. Абстрактные классы и чистые виртуальные функции. Интерфейс
- •8. Дружественность. Дружественные классы и функции.
- •10. Шаблоны классов
- •9. Вложенные классы. Внутреннее и внешнее определение.
- •11.Создание экземпляров шаблона. Инстанцирование.
- •12.Шаблоны и наследование.
- •13.Терминология шаблонов.
- •14. Параметры и аргументы шаблона.
- •15. Шаблоны компонентных функций
- •16. Полная специализация шаблонов.
- •17. Частичная специализация шаблонов.
- •18. Перегрузка операций. Основные понятия.
- •19. Перегрузка унарных операций.
- •20. Перегрузка бинарных операций.
- •Int test() {
- •Int test() {
- •Int test() {
- •// Делаем что-то
- •Вопрос 23
- •24. Группировка и композиция исключений. Повторная генерация. Перехват всех исключений.
- •25. Автоматическое управление ресурсами. Методика raii.
- •Void f() { FileOpen("myfile.Txt", "rt"); //здесь выполняем нужную работу с файлом //... }
- •Void f (int a) throw (x2, x3)
- •27. Стандартная библиотека. Организация стандартной библиотеки
- •28. Тип вектора. Вложенные типы. Итераторы. Доступ к элементам
- •29.Тип Вектора. Конструкторы. Операции со стеком. Списочные операции. Размеры и емкость.
- •30. Стандартные контейнеры. Вопросы производительности операций.
- •31. Процесс разработки по. Цели и этапы проектирования.
- •32. Процесс разработки по. Выявление классов. Определение операций.
- •33. Процесс разработки по. Определение взаимосвязей. Определение интерфейсов.
- •Этап 3: выявление зависимостей
- •Этап 4: определение интерфейсов
- •34. Паттерны проектирования. Основные паттерны.
- •35. Тестирование по. Методы тестирования.
#include <boost/scoped_ptr.hpp>
Int test() {
boost::scoped_ptr<int> p1(new int(6));
boost::scoped_ptr<int> p2(new int(1));
p1 = p2; // Нельзя!
}
Оно и понятно, если бы было разрешено присваивание, то и p1 и p2 будут указывать на одну и ту же область памяти. А по выходу из функции оба удалятся. Что будет? Никто не знает. Соответственно, этот пойнтер нельзя передавать и в функции. Тогда зачем он нужен? Советую применять его как указатель-обертка для каких-либо данных, которые выделяются динамически в начале функции и удаляются в конце, чтобы избавить себя от головной боли по поводу корректной очистки ресурсов
std::auto_ptr
Чуть-чуть улучшенный вариант предыдущего, к тому же он есть в стандартной библиотеке (хотя в C++11 вроде как deprecated). У него есть оператор присваивания и конструктор-копировщик, но работают они несколько необычно. Поясняю:
#include <memory>
Int test() {
std::auto_ptr<MyObject> p1(new MyObject);
std::auto_ptr<MyObject> p2;
p2 = p1;
}
Теперь при присваивании в p2 будет лежать указатель на MyObject (который мы создавали для p1), а в p1 не будет ничего. То есть p1 теперь обнулен. Это так называемая семантика перемещения. Кстати, оператор копирования поступает таким же образом. Зачем это нужно? Ну например у вас есть функция, которая должна создавать какой-то объект:
std::auto_ptr<MyObject> giveMeMyObject();
Это означает, что функция создает новый объект типа MyObject и отдает его вам в распоряжение. Понятней станет, если эта функция сама является членом класса (допустим Factory): вы уверены, что этот класс (Factory) не хранит в себе еще один указатель на новый объект. Объект ваш и указатель на него один. В силу такой необычной семантики auto_ptr нельзя использовать в контейнерах STL. Но у нас есть shared_ptr.
std::shared_ptr (С++11)
Умный указатель с подсчетом ссылок. Что это значит. Это значит, что где-то есть некая переменная, которая хранит количество указателей, которые ссылаются на объект. Если эта переменная становится равной нулю, то объект уничтожается. Счетчик инкрементируется при каждом вызове либо оператора копирования либо оператора присваивания. Так же у shared_ptr есть оператор приведения к bool, что в итоге дает нам привычный синтаксис указателей, не заботясь об освобождении памяти.
#include <memory> // либо <tr1/memory> для компиляторов, еще не поддерживающих C++11
#include <iostream>
Int test() {
std::shared_ptr<MyObject> p1(new MyObject);
std::shared_ptr<MyObject> p2;
p2 = p1;
if (p2)
std::cout << "Hello, world!\n";
}
Теперь и p2 и p1 указывают на один объект, а счетчик ссылок равен 2, По выходу из скоупа счетчик обнуляется, и объект уничтожается. Мы можем передавать этот указатель в функцию:
int test(std::shared_ptr<MyObject> p1) {
// Делаем что-то
}
Заметьте, если вы передаете указатель по ссылке, то счетчик не будет увеличен. Вы должны быть уверены, что объект MyObject будет жив, пока будет выполняться функция test. Итак, smart pointers это хорошо, но есть и минусы. Во-первых это небольшой оверхед, но я думаю у вас найдется несколько тактов процессора ради такого удобства. Во-вторых это boiler-plate, например
std::tr1::shared_ptr<MyNamespace::Object> ptr = std::tr1::shared_ptr<MyNamespace::Object>(new MyNamespace::Object(param1, param2, param3))
Это частично можно решить при помощи дефайнов, допустим:
#define sptr(T) std::tr1::shared_ptr<T>
Либо при помощи typedef. В-третьих, существует проблема циклических ссылок. Рассматривать ее здесь не буду, чтобы не увеличивать статью. Так же остались нерассмотренными boost::weak_ptr, boost::intrusive_ptr и указатели для массивов.
Итераторы
Для доступа к элементам некоторого множества элементов алгоритмы stl используют специальные объекты, называемые итераторами. В контейнерных типах stl они доступны через методы класса (например, begin() в шаблоне класса vector). Функциональные возможности указателей и итераторов близки, так что обычный указатель тоже может использоваться как итератор.
Операции над итераторами
