Стенли Липпман - Язык программирования C++. Пятое издание
- Название:Язык программирования C++. Пятое издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2014
- Город:Москва
- ISBN:978-5-8459-1839-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стенли Липпман - Язык программирования C++. Пятое издание краткое содержание
Вы держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под
. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. В соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.
С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать их наилучшие способы применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.
Стенли Б. Липпман Жози Лажойе Барбара Э. Му • Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием
• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования
• Изучите принципы и узнайте почему язык С++11 работает именно так
• Воспользуйтесь множеством перекрестных ссылок, способных помочь вам объединить взаимосвязанные концепции и проникнуть в суть
• Ознакомьтесь с современными методиками обучения и извлеките пользу из упражнений, в которых подчеркиваются ключевые моменты, позволяющие избежать проблем
• Освойте лучшие методики программирования и закрепите на практике изученный материал
Исходный код примеров можно загрузить с веб-страницы книги на сайте издательства по адресу: http://www.williamspublishing.com
Язык программирования C++. Пятое издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Ненужного копирования можно избежать, написав функцию swap()для класса Foo. Но версию функции swap()для класса Fooможно написать так:
void swap(Foo &lhs, Foo &rhs) {
// Ошибка: эта функция использует библиотечную версию
// функции swap(), а не версию класса HasPtr
std::swap(lhs.h, rhs.h); // обменять другие члены класса Foo
}
Этот код нормально компилируется и выполняется. Однако никакого различия в производительности между этим кодом и просто использующим стандартную версию функции swap()не будет. Проблема в том, что здесь явно запрошен вызов библиотечной версии функции swap(). Однако нужна версия функции не из пространства именstd, а определенная в классе HasPtr.
Правильный способ написания функции swap()приведен ниже.
void swap(Foo &lhs, Foo &rhs) {
using std::swap;
swap(lhs.h, rhs.h); // использует функцию swap() класса HasPtr
// обменять другие члены класса Foo
}
Все вызовы функции swap()обходятся без квалификаторов. Таким образом, каждый вызов должен выглядеть как swap(), а не std::swap(). По причинам, рассматриваемым в разделе 16.3, если есть специфическая для типа версия функции swap(), она будет лучшим соответствием, чем таковая из пространства имен std. В результате, если у типа есть специфическая версия функции swap(), вызов swap()будет распознан как относящийся к специфической версии. Если специфической для типа версии нет, то (с учетом объявления usingдля функции swap()в области видимости) при вызове swap()будет использована версия из пространства имен std.
У очень осторожных читателей может возникнуть вопрос: почему объявление usingфункции swap()не скрывает объявление функции swap()класса HasPtr (см. раздел 6.4.1). Причины, по которым работает этот код, объясняются в разделе 18.2.3.
swap()в операторах присвоенияКлассы, определяющие функцию swap(), зачастую используют ее в определении собственного оператора присвоения. Эти операторы используют технологию, известную как копия и обмен (copy and swap)). Она подразумевает обмен левого операнда с копией правого:
// обратите внимание: параметр rhs передается по значению. Это значит,
// что конструктор копий класса HasPtr копирует строку в правый
// операнд rhs
HasPtr& HasPtr::operator=(HasPtr rhs) {
// обменивает содержимое левого операнда с локальной переменной rhs
swap(*this, rhs); // теперь rhs указывает на память, которую
// использовал этот объект
return *this; // удаление rhs приводит к удалению указателя в rhs
}
В этой версии оператора присвоения параметр не является ссылкой. Вместо этого правый операнд передается по значению. Таким образом, rhs— это копия правого операнда. Копирование объекта класса HasPtrприводит к резервированию новой копии строки данного объекта.
В теле оператора присвоения вызывается функция swap(), обменивающая переменные-члены rhsс таковыми в *this. Этот вызов помещает указатель, который был в левом операнде, в rhs, и указатель, который был в rhs,— в *this. Таким образом, после вызова функции swap()указатель-член в *thisуказывает на недавно зарезервированную строку, являющуюся копией правого операнда.
По завершении оператора присвоения параметр rhsудаляется и выполняется деструктор класса HasPtr. Этот деструктор освобождает память, на которую теперь указывает rhs, освобождая таким образом память, на которую указывал левый операнд.
В этой технологии интересен тот момент, что она автоматически отрабатывает присвоение себя себе и изначально устойчива к исключениям. Копирование правого операнда до изменения левого отрабатывает присвоение себя себе аналогично примененному в нашем первоначальном операторе присвоения (см. раздел 13.2.1). Это обеспечивает устойчивость к исключениям таким же образом, как и в оригинальном определении. Единственный код, способный передать исключение, — это оператор newв конструкторе копий. Если исключение произойдет, то это случится прежде, чем изменится левый операнд.
Операторы присвоения, использующие копию и обмен, автоматически устойчивы к исключениям и правильно отрабатывают присвоение себя себе.
Упражнение 13.29. Объясните, почему вызов функции swap()в вызове swap(HasPtr&, HasPtr&)не приводит к бесконечной рекурсии.
Упражнение 13.30. Напишите и проверьте функцию swap()для подобной значению версии класса HasPtr. Снабдите свою функцию swap()оператором вывода примечания о ее выполнении.
Упражнение 13.31. Снабдите свой класс оператором <и определите вектор объектов класса HasPtr. Вставьте в вектор несколько элементов, а затем отсортируйте его ( sort()). Обратите внимание на то, когда вызывается функция swap().
Упражнение 13.32. Получит ли преимущества подобная указателю версия класса HasPtrот определения собственной функции swap()? Если да, то в чем это преимущество? Если нет, то почему?
13.4. Пример управления копированием
Несмотря на то что управление копированием обычно необходимо для классов, резервирующих ресурсы, управление ресурсами не единственная причина определения этих функций-членов. У некоторых классов может быть необходимость в учете или других действиях, выполняемых функциями управления копированием.
В качестве примера, нуждающегося в управлении копированием класса для учета, рассмотрим два класса, которые могли бы использоваться в приложении обработки почты. Эти классы, Messageи Folder, представляют соответственно сообщение электронной (или другой) почты и каталог, в котором могло бы находиться это сообщение. Каждое сообщение может находиться в нескольких папках. Но может существовать только одна копия содержимого любого сообщения. Таким образом, если содержимое сообщения изменится, эти изменения отображаются при просмотре данного сообщения в любой из папок.
Для отслеживания того, какие сообщения в каких папках находятся, каждый объект класса Messageбудет хранить набор указателей на объекты класса Folder, в которых они присутствуют, а каждый объект класса Folderбудет содержать набор указателей на его объекты класса Message. Эту конструкцию иллюстрирует рис. 13.1.
Рис. 13.1. Проект классов Messageи Folder
Интервал:
Закладка: