
400 страниц. Альфа-книга, 2017
Kurt Guntheroth. Optimized C++. Proven Techniques for Heightened Performance. O’Reilly, 2016
«Приветствую вас! Меня зовут Курт, и я кодоголик».
Подход обстоятельный. В начале книги описывается закон Амдала — улучшение времени выполнения \(S_T\):
\(S_T = \dfrac{1}{(1-P)+\frac{P}{S_p}}\),
где \(P\) — доля оптимизированного общего времени выполнения, \(S_p\) — показатель улучшения в оптимизированной части \(P\). Например, если некоторая функция выполнялась 80 процентов всего времени работы программы, а улучшенная её версия стала работать на 30 процентов быстрее, иначе говоря, \(P=0{,}8\), \(S_p=1{,}3\), то \(S_T\approx 1{,}22\).
Глава «Оптимизация, влияющая на поведение компьютера» — очерк того, с какими абстракциями аппаратного и программного обеспечения приходится иметь дело. Большая часть тем — это последовательное улучшение некоторого базового примера.
Глава «Измерение производительности» рассказывает о физике процесса, о стандартах (как они определяют прецизионность, истинность и точность — accuracy, trueness, precision). С историческими справками и примерами. И так вплоть до класса-секундомера.
Глава «Оптимизация использования строк» описывает проблемыб из-за которых проседает производительность, анализирует их и предлагает пути решения. Здесь предлагаются варианты работы со стандартными классами, C-строками, std::string_view и разными сторонними библиотеками (folly::fbstring, Folly и другими).
В главе «Оптимизация алгоритмов» обсуждаются некоторые детали анализа сложности, частые заблуждения о сложности известных алгоритмов, а также шаблоны оптимизации (предварительные вычисления, отложенные вычисления и другие).
Сложно коротко описать, о чём глава «Оптимизация переменных в динамической памяти», название не отражает всего спектра тем, которые там излагаются. Может быть, самая важная глава в книге.
Глава «Оптимизация инструкций» рассказывает о понятии инварианта, удалении скрытых вызовов и кода из функций, а ещё о том, что в какой-то момент нужно и остановиться:
«Мудрые разработчики, занимающиеся оптимизацией кода, знают, что лучше не ослаблять дизайн без уважительной причины и не гоняться за каждой виртуальной функцией программы со скальпелем в руке».
Здесь же автор горячо рекламирует книгу Генри С. Уоррена-мл. «Алгоритмические трюки для программистов» (Henry S. Warren, Jr. Hacker’s Delights).
Глава «Использование лучших библиотек» немного рассказывает о стандартной библиотеке, о заблуждениях, связанных с ней, о затем — о том, каким базовым принципам должен следовать разработчик хорошей библиотеки.
«Оптимизация сортировки и поиска», «Оптимизация структур данных», «Оптимизация ввода-вывода», «Оптимизация параллельности» — главы о стандартной библиотеке и других библиотеках.
Глава «Оптимизация управления памятью» рассказывает в том числе про размещающий оператор new, функции для работы с памятью в стиле C и разного рода библиотеки.
Книга обстоятельная, но доходчивая. С редкими врезками с историями из жизни. Ещё бы «каркасы» в переводе были «фреймворками»...
264 страницы. ДМК, 2006
Stephen C. Dewhurst. C++ Gotchas. Avoiding Common Problems in Coding and Design. Addison-Wesley, 2003
99 советов, сгруппированных по темам. Содержание: основы, синтаксис, препроцессор, преобразования, инициализация, управление памятью и ресурсами, полиморфизм, проектирование классов, проектирование иерархий.
Все плохие примеры кода написаны на сером фоне, хорошие — на белом (по большей части).
Примерно половина книги — довольно простые, но хитрые примеры.
h.*value = 1.85
*(double *)((char *)&h+(value-1)) = 1.85
240 страниц. Символ-Плюс, 2007
Stephen C. Dewhurst. C++ Common Knowledge. Addison-Wesley, 2005
Оригинальное название — отсылка к колонке Стивена Дьюхерста Common Knowledge в журнале C++ Report (главредом был Герб Саттер).
Из отзыва Стенли Липпмана мы узнаём: «Стив научил меня C++. Это было в далёком 1982 или 1983. Я думаю, он тогда только вернулся с последипломной практики, которую проходил вместе с Бьерном Страуструпом в научно-исследовательском центре Bell Laboratories. Стив — один из невоспетых героев, стоящих у истоков».
63 темы без группировки. Это и «старые» вещи вроде указателей на указатели, а также тонкости реализации ООП в C++, шаблоны, STL, некоторые шаблоны проектирования.
Далее идут четыре перевода книг Скотта Мейерса. Для удобства представлено содержание каждой из них. Отдельные части могут дублироваться, но в целом это разные книги. В приложении к переводу книги 2006 года есть таблицы соответствия между изданиями.
В предисловии к третьему изданию говорится, что первый вариант книги «Эффективное использование C++» появился ещё в 1991 году (перевода этого издания, по-видимому, нет). Второе издание 1997 года почти полностью его повторяло.
304 страницы. ДМК Пресс, 2000
Scott Meyers. More Effective C++. 35 New Ways to Improve Your Programs and Designs. Addison-Wesley, 1996
Книга хоть и старая, но актуальности не теряет. Практически чек-лист для тех, кто изучили основы и намереваются разобраться глубже.
Приложения: список рекомендуемой литературы, реализация шаблона auto_ptr (объявлен устаревшим в C++11, удалён в C++17).
Для примера посмотрим на 5-й совет: «Опасайтесь определяемых пользователем функций преобразования типа».
class Rational {
public:
...
operator double() const; // Преобразует Rational
// к типу double.
};
Объект класса Rational теперь можно явно или неявно приводить к типу double.
Rational r(1, 2); // Значение r равно 1/2.
double d = 0.5 * r; // Преобразует r к типу
// double, а затем выполняет
// операцию умножения.
Если для этого типа не перегрузить оператор <<, то cout << r выведет 0.5, а например, не 1/2.
А вы знали, почему тип возвращаемого значения у перегруженного оператора постинкремента operator++(int) следует делать константным? Чтобы вызов i++++ не работал (как он не работает для типа int), тем более, что всё равно i будет увеличиваться единожды. А почему не стоит обрабатывать исключения по указателю? Как убедиться, что объект создан в куче? А запретить создавать объекты класса в куче? Вопросы вполне прикладные.
Книга написана простым языком, местами с юмором. Например, автор сравнивает ленивые вычисления с тем, как пятилетний ребёнок до конца откладывает уборку в комнате, пока не услышит, как родители пойдут смотреть на наведённый порядок.
Некоторые вещи звучат странно, например, совет делать конструкторы и функции, не являющиеся членами класса, виртуальными. Это невозможно, так просто называется некая техника.
Книгу писали давно, поэтому будут такие пассажи: «Функция operator new[] добавлена в стандарт языка сравнительно недавно». Спецификация исключений (правило 14), умные указатели (правило 28) — это уже всё устарело.
Перевод не идеальный. Так, «a const object» стал «объектом с атрибутом const», который вообще-то квалификатор. В «отслоённых объектах» можно не сразу угадать sliced objects, то есть объекты, которые подверглись срезке (slicing). А name mangling назван «коррекцией имён». Есть опечатки, некоторые — смешные («статистические объекты»).
Перевод или неаккуратно набирали, или плохо вычитали результат распознавания символов.
Амперсанд легко прекратился в s.
void uppercasify(string& str); // changes all chars in
// str to upper case
void uppercasify(strings str); // Переводит все символы
// в str в верхний регистр
240 страниц. ДМК Пресс, Питер 2006
Scott Meyers. More Effective C++. 35 New Ways to Improve Your Programs and Designs. Addison-Wesley, 1998
По какой-то причине «35 новых способов улучшить ваши программы и проекты» в переводе стали 50-ю.
Сперва — о паре устаревших вещей. Трудно сказать, может, в 1998 году предостережение из четвёртого совета «Предпочитайте комментарии в стиле C++» (в целом верного и хорошего) имело смысл, но сейчас трудно об этом судить:
#define LIGHT_SPEED 3e8 // м/сек (в вакууме).
Совет 27 «Явно запрещайте использование нежелательных функций-членов, создаваемых компилятором по умолчанию» предлагает делать такие члены закрытыми, а стандарт C++11 для этого предлагает = delete.
Хоть книга и ровесница первого международного стандарта C++98, в остальном она абсолютно полезна и актуальна. Там есть всё или почти всё, что нужно знать тем, кто изучают язык и хотят глубже погрузиться в практику его использования.
300 страниц. ДМК Пресс, 2006
Scott Meyers. Effective C++. 55 Specific Ways to Improve Your Programs and Designs. Addison-Wesley, 2005
Приложения: «За пределами „Эффективного использования C++“», соответствие правил во втором и третьем изданиях.
Книгу можно назвать переработкой прошлой. Видно, что она готовилась в преддверии стандарта C++11 (этот стандарт имел рабочее название C++0x, потому что его планировали выпустить ещё до 2010 года): в книге используются какие-то вещи из TR1 (Technical Report 1) — новые шаблоны классов и функций в пространстве имён std::tr1, которые стали частью стандартной библиотеки C++11. Например std::tr1::shared_ptr, который позже стал std::shared_ptr.
Вот пример совета. Совет 32 «Используйте открытое наследование для моделирования отношения „является“».
class Penguin : public Bird {
public:
virtual void fly() {error("Попытка заставить пингвина летать!");}
...
};
«Важно понимать, что это здесь имеется в виду не совсем то, что вам могло показаться. Мы не говорим: „Пингвины не могут летать“, а лишь сообщаем: „Пингвины могут летать, но с их стороны было бы ошибкой это делать“. В чём разница? Во времени обнаружения ошибки».
Как это стало привычным, что-то устарело (std::auto_ptr), где-то есть «особенности» перевода (deleter — «чистильщик»).
304 страницы. «Вильямс», 2016
Scott Meyers. Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14. O’Reilly, 2015
Эта книга охватывает стандарт C++11. Хорошее дополнение к предыдущей.
Написано с долей юмора, как и всегда:
«Ну, конечно же, вы отлично всё это знаете. Да, да, древняя история: Месопотамия, династия Цинь, Владимир Красное Солнышко (отсебятина переводчика, в оригинале его не было. — Прим. DZ), FORTRAN, C++98... Но времена изменились, а с ними изменились и правила генерации специальных функций-членов в C++».
512 страниц. Бином, 2001
Chris H. Pappas, William H. Murray, III. Debugging C++. Troubleshooting for Programmers. McGraw-Hill, 2000
Есть и более новые переиздания, но ждать большего от них не нужно.
Книга в основном посвящена разработке под Windows, все примеры, ключи и прочее — относятся к Visual C++. Часто разговор идёт о библиотеке MFC.
Много старья: венгерская нотация, структурные диаграммы, древние справочные системы, <iostream.h> (разнице с <iostream> посвящён целый параграф), DHTML и прочее.
Базовые принципы никогда не устареют (оформление кода, логические vs. синтаксические ошибки), немного ассемблера, много скриншотов. Когда-то и для кого-то книга была хороша, но не сейчас.
400 страниц. Вильямс, 2003
Herb Sutter. Exceptional C++. 87 New Engineering Puzzles, Programming Problems, and Solutions. Addison-Wesley, 2002
Содержание:
Так ли нужен тип bool? Как на практике работает поиск Кёнига? Какие ошибки легко совершить при работе с макросами? Как создать класс регистронезависимой строки? Как эффективно использовать STL? Как сымитировать сложенную функцию (книга написана до C++11, где появились лямбда-функции)? Книга — сборник таких вот вопросов и задач с подробными решениями.
272 страницы. Вильямс, 2005
Herb Sutter. Exceptional C++ Style. 40 New Engineering Puzzles, Programming Problems, and Solutions. Addison-Wesley, 2004
Оглавление:
В предисловии обсуждается фотография с обложки — вид на Будапешт. Сравниваются архитектура строительства и архитектура программного обеспечения. Своеобразное эссе о строительстве и поддержке (здание парламента на фотографии реставрируют почти с момента постройки в 1902, в особенности скульптуры из плохо подобранного материала).
Затем обсуждается метод Сократа («Цель книги — помочь читателю сделать верные выводы, как из хорошо известного ему материала, так и из только что изученного»). Вполне точно сказано, это правда для книг этой серии.
Почему у шаблонов функций не бывает специализаций? Что такое export и «почему все так старательно игнорируют эту возможность»? Что такое невиртуальный интерфейс (Non-Virtual InterfaceNVI) и зачем он нужен? Почему delete[] не требует передавать размер? Где тогда он хранится? Почему этот код вообще работает?
int main() {
if( true ); // 1: OK
if( 42 ); // 2: OK
}
И много других вопросов, ответы на которые, пожалуй, стоило бы знать.
224 страницы. Вильямс, 2005
Herb Sutter, Andrei Alexandrescu. C++ Coding Standards. 101 Rules, Guidelines, and Best Practices. Addison-Wesley, 2005
Авторы в советах (почти всегда) следуют шаблону: краткое содержание, мотивировка, примеры, исключения, ссылки на литературу.
Книга написана одновременно строгим и человеческим языком, порой с юмором:
«Первое правило оптимизации: не оптимизируйте. Второе правило оптимизации (только для экспертов): не оптимизируйте ни в коем случае».
Содержание: организация, стиль проектирования, стиль кодирования, функции и операторы, классы и наследование; конструкторы, деструкторы и копирование; пространства имён, шаблоны, обработка ошибок и исключений, контейнеры и алгоритмы STL, безопасность типов. При всём при том авторы не стараются написать обо всём на свете, а осознанно выбрасывают вещи, которые, по их мнению, и так должны быть обычной практикой:
«„Не возвращайте указатель или ссылку на локальную переменную“ — хороший совет, но он не включён в данную книгу, поскольку практически все компиляторы выдают соответствующее предупреждение...»
Здесь за двадцать лет тоже что-то устарело, например, совет о том, что не нужно без лишней необходимости пользоваться спецификацией исключений.
496 страниц. Вильямс, 2015
Robert C. Seacord. Secure Coding in C and C++. Addison-Wesley, 2013
Оглавление:
Некоторые главы написаны в соавторстве.
Книга серьёзная. Она посвящена вопросам безопасности для языков программирования C и C++, а также связанных с ними библиотек. В книге не освещаются вопросы безопасности взаимодействия с внешними системами (базами данных, веб-серверами).
Люди писали серьёзные. CERT (Computer Emergency Response Team) — группа в институте Университете Карнеги-Меллон, финансируемом правительством США. Работает с 1988 года, с тех самых пор, когда десять процентов всех интернет-систем поразил червь Морриса. Автор — участник этой группы.
Книга содержит глубокий анализ причин того, почему языки C и C++ иногда .
«В исходном документе по стандартизации языка C содержится ряд руководящих принципов. Из них п. 6 наиболее чётко формулирует источник проблем, связанных с безопасностью. [...] На весеннем совещании WG14 2007 года в Лондоне, где обсуждался стандарт C11, была высказана мысль, что п. а следует перефразировать как „доверяй, но проверяй“. П. б остался нетронутым, так как он критичен для успеха языка программирования C».
Содержание пункта 6:
а) Доверять программисту.
б) Не мешать программисту делать то, что он должен сделать.
в) Язык должен быть небольшим и простым.
г) Предоставлять только один способ выполнения операции.
д) Язык должен быть простым, даже если это не гарантирует переносимость.
Описываются виды поведения,
«Большинство уязвимостей, описанный в этой книге, являются результатом использования в коде неопределённого поведения».
Первая содержательная глава — про строки. И, наверное, неспроста. Строки есть разных видов (обычные, широкие, многобайтовые), понятно что нужно следить за переполнением (эта тема разобрана полностью, вплоть до того, что происходит со стеком и как борются с атаками на уровне компиляторов и операционных систем), но также есть много других проблемных мест:
«Тип строкового литерала с C представляет собой массив символов элементов типа char в C, но в C++ это массив элементов типа const char. [...] иногда компиляторы хранят несколько одинаковых строковых литералов по одному и тому же адресу, так что изменение одного такого литерала может привести к изменению других литералов».
Книга не просто интересная, её можно назвать захватывающей:
«Программа tar использовалась для создания архивных файлов в системах UNIX. В рассматриваемом случае программа tar в системе Solaris 2.0 необъяснимо включала в архив фрагменты файла /etc/passwd, что является примером утечки информации, которая позволяет взломать систему безопасности.
Проблема в данном случае заключалась в том, что утилита tar не инициализировала динамически выделенную память, которая использовалась для чтения блоков данных с диска. К сожалению, перед выделением этого блока утилита tar выполняла системный вызов для просмотра информации о пользователе в файле /etc/passwd. Соответствующий блок памяти освобождался вызовом функции free() так же, как и функция malloc(), не инициализирует (в данном случае — не очищает) используемую память. Эта уязвимость была исправлена путём замены вызова функции malloc() вызовом calloc() в программе tar. Существующее решение чрезвычайно „хрупкое“, так как любые изменения могут привести к тому, что произойдёт утечка важной информации при перераспределении памяти в другом месте программы, вызывая у программиста déjà vul».
Déjà vu — «уже увиденное», déjà vul — от слова vulnerability, «уязвимость».
Всё с понятными объяснениями, всеми нужными картинками и даже комиксами XKCD.
736 страниц. КУДИЦ-ОБРАЗ, 2006
Matthew Wilson. Imperfect C++. Practical Solutions for Real-Life Programming. Addison Wesley, 2005
Краткое содержание: базовые концепции, выживание в условиях реального мира (двоичный интерфейс приложения, таблицы виртуальных функций и т. д.), языковые проблемы, осознанные преобразования, операторы, расширение C++.
Приложения: компиляторы и библиотеки, «Остерегайтесь самомнения!» (рефлексия автора по поводу неправильного использования перегрузки операторов, принципа DRY и других вещей в его прошлых проетках), Arturius (проект, названный в честь короля Артура, известного своим Круглым столом; идея проекта была в том, чтобы код компилировался сразу многими компиляторами, чтобы можно было добиться как можно большей переносимости; сейчас сайт проекта недоступен, на компакт диске — только скриншот и сохранённая веб-страница проекта).
Ещё в самом начале автор говорит, что надеется на то, что читатели знакомы с книгами Мейерса, Саттера и Страуструпа, ссылается на книги этих и других авторов (Дьюхерста, Алекскандреску и др.).
Очень подробно разбирается, как разные компиляторы ведут себя в каких-то ситуациях. Книга многословная, и нельзя сказать, что полезная для всех, скорее — для разработчиков библиотек. Хотя автор уверяет, что всего лишь хочет помочь сделать код более переносимым и менее подверженным ошибкам.
Вот первый содержательный пример из книги.
template< typename D
, typename B
>
struct must_have_base
{
~must_have_base()
{
void(*p)(D*, B*) = constraints;
}
private:
static void constraints(D* pd, B* pb)
{
pb = pd;
}
};
Здесь на этапе компиляции (закрытая функция статическая) проверяется ограничение, что у одного класса есть другой в качестве базового. И такие вещи всю книгу.
В переводе Batman стал суперменом, Йоги Берра — йогом по имени Берра. Опечаток больше, чем ошибок компиляции, когда случайно пропустишь точку с запятой.
240 страниц. Питер, 2004
Steve Oualline. How Not to Program in C++. 111 Broken Programs and 3 Working Ones, or Why Does 2 + 2 = 5986? No Starch Press, 2003
Оглавление первой части:
Вторая часть — подсказки. Третья часть — ответы.
У книги, пожалуй, самое странное посвящение:
«Посвящаю эту книгу моей Чи. Если бы она не вдохновляла меня, я бы никогда не закончил свою работу.
Книга ни в коем случае не посвящается моей жене Карен, потому что мою жену зовут вовсе не Карен. У меня никогда не было жены по имени Карен, и я понятия не имею, о ком идёт речь».
Из введения мы узнаём детали этой истории, но не все.
«Посвящаю эту книгу моей жене Чи Муй Вонг. Если бы она не пошла на курсы программирования и не узнала, что программиста из неё не получится, то этой книги не существовало бы (кстати, автором первой нерабочей программы „Hello, world!“, приводимой в этой книге, был её преподаватель)».
Какие-то задачи интересные, например, надо угадать, какое неявное преобразование повлияло на результат. Какие-то даже глупые, например, где автор «забыл» поставить перенос в конце строки или пробелы в выводе, так что он «слипся».
К каждой задаче есть подсказка и ответ (в конце книги).
/*******************************************
* "Стандартная" программа Hello world *
*******************************************/
#include <iostream>
void main(void)
{
std::cout << "Hello world!\n";
}
Это первая задача в книге, но подсказка к ней идёт под номером 228, а ответ — под номером шесть.
Странная особенность книги — постоянные врезки, никак не связанные с задачами и языком C++ вообще.
«Если в чековой книжке кончались пустые бланки, клиент получал бланк у кассира. Конечно, на таком бланке номер счёта указан не был, поэтому клиенту приходилось вписывать его вручную.
Некий мошенник напечатал собственный вариант депозитных бланков. Внешне они ничем не отличались от обычных «общих» бланков, но на них магнитными чернилами был нанесён номер счёта мошенника.
Затем он пошёл в банк и подложил эти бланки в общий лоток.
Афера работала так: клиент приходил в банк, чтобы положить деньги на счёт, и получал один из поддельных бланков. Он заполнял бланк и вносил деньги. Поскольку на бланке был напечатан номер счёта, компьютер автоматически обрабатывал его и вносил деньги на этот счёт. На номер счёта, вручную написанный на бланке, он не обращал внимания. Другими словами, мошенник присваивал чужие депозиты.
Сыщик, которому поручили это дело, был озадачен. Вносимые деньги исчезали, и никто не понимал, как это происходит. Удалось выяснить, что проблема возникает только при внесении денег непосредственно в банке. Сыщик решил попробовать сделать большое количество вкладов и посмотреть, что будет. Поскольку он использовал собственные деньги, ему приходилось ограничиться мелкими вкладами... очень, очень мелкими. Каждым вклад был на сумму в шесть центов. Сыщик потратил целую неделю. Он приходил в банк, заполнял бланк, вставал в очередь, вносил шесть центов, потом заполнял новый бланк, вставал в очередь, вносил шесть центов и т. д. Кассиры решили, что он сошёл с ума. Но вот один из вкладов исчез. Тогда по требованию сыщика в банке проверили, не вносил ли кто-нибудь ещё в этот день сумму шесть центов. Такой вклад нашли, и вора поймали».
«Команда Unix true не делает ничего. Вообще говоря, первая версия программы представляла собой пакетный файл (сценарий) длиной ноль строк. За прошедшие годы в этот файл добавлялась различная информация систем управления исходными текстами, пока программа из нуля строк не приняла следующий вид...»
#! /bin/sh
#
# @(#)true.sh 1.5 88/02/07 SMI; from UCB
#
exit 0
И такие байки, факты, анекдоты и истории из жизни занимают почти полкниги.