Дочитал Смаллиана.
Сейчас читаю
Бьерн Страуструп
Язык программирования C++
СПб.: М.: "Невский диалект" - "Издательство Бином", 1999 г., 991 стр.
Третье издание
Перевод с англ. С. Анисимова и М. Кононова под редакцией Ф. Андреева и А. Ушакова
The C++ Programming Language. Third edition. Bjarne Stroustrup. AT&T Labs. Murray Hill, New Jarsey
To use: механизм Assert
Цитаты:
стр. 52 стр. 53 стр. 81 стр. 111 стр. 115 стр. 152 стр. 173 стр. 207 стр. 263 стр. 319 стр. 336 стр. 531 стр. 594 стр. 615 стр. 631 стр. 708 стр. 792 стр. 912 стр. 52
Вопрос "Как писать хорошие программы на С++?" напоминает вопрос "Как писать хорошую английскую прозу?". Есть два совета: "Знай, что хочешь сказать" и "Тренируйся. Подражай хорошему стилю". Оба совета годятся как для С++, так и для английской прозы, и им обоим одинаково сложно следовать.
стр. 53
Обширный список литературы
стр. 81
Зачем тратить время на обучение, когда невежество даётся даром?
-- Хоббс
стр. 111
Типы unsigned (без знака) идеально подходят для задач, в которых память интерпретируется как массив битов. Использование unsigned вместо int с целью заработать лишний бит для представления положительных целых почти всегда оказывается неудачным решением. Использование же объявления unsigned для гарантии того, что целое будет неотрицательным, почти никогда не сработает из-за правил неявного преобразования типов.
стр. 115
В качестве элементов перечисления можно определить именованные целые константы. Например:
enum {ASM, AUTO, BREAK};
определяет три целые константы, называемые элементами перечисления, и присваивает им значения.
стр. 152
Считывание из потока ввода -- часто самая запутанная часть программы. Это происходит потому, что программа должна общаться с человеком -- учитывать его капризы, привычки и совершенно необъяснимые на первый взгляд ошибки. Попытка заставить человека поступать так, как это удобно компьютеру, обычно считается (и справедливо) оскорбительной.
стр. 173
Создание значения типа T из значения e можно выразить при помощи функционально обозначения T(e). Например:
void f(double d)
{
int i = int(d); // отбросить дробную часть d
complex z = complex(d); // создать комплексное число из d
}
Конструкцию T(e) иногда называют функциональным стилем приведения (типов). Для встроенного типа T запись T(e) эквивалентна static_cast(e). К сожалению, это подразумевает, что использование T(e) не всегда безопасно.
стр. 207
David Kahn The Codebreakers, Macmillan, 1967, New York
(алгоритм шифровки через xor)
стр. 263
Часто функция, возвращающая ссылку, является хорошей альтернативой глобальной переменной. Например:
int& use_count()
{
static int uc = 0;
return uc;
}
В этом случае вызов use_count() действует как глобальная переменная за исключением того, что её инициализация происходит при первом использовании.
...
Если завершение программы осуществляется вызовом стандартной библиотечной функции exit(), то при этом вызываются деструкторы для всех созданных статических объектов. Если же завершение программы осуществляется вызовом стандартной библиотечной функции abort(), деструкторы не вызываются.
стр. 319
Однако в тех случаях, когда копирующий конструктор по умолчанию имеет правильный смысл, я предпочитаю полагаться на это умолчание. Это короче, чем я могу написать, а читающие код должны понимать умолчания. Кроме того, компилятор знает об этом умолчании и о возможностях его оптимизации. Написание почленного копирования классов с большим количеством членов данных вручную -- занятие утомительное, и при этом можно наделать массу ошибок.
...
В принципе, копирующие конструкторы используются при простых инициализациях типа
complex x = 2; // создаёт complex(2), затем инициализирует им x
complex y = complex(2,0); // создаёт complex(2,0), затем инициализирует им y
Однако от вызовов копирующих конструкторов можно легко избавиться. Мы могли бы с тем же успехом записать:
complex x(2); // проинициализировать x значением 2
complex y(2,0); // проинициализировать y значением (2,0)
стр. 336
(функции-подобные объекты или просто объекты-функции)
class Add {
complex val;
public:
Add(complex c) { val = c; }
Add(double r, double i) { val = complex(r,i); } // сохранить значение
void operator () (complex& c) const { c += val; }
};
Объект класса Add инициализируется комплексным числом, и при вызове с использованием () прибавляет это число к аргументу. Например:
void h(vector& aa, list& ll, complex z)
{
for_each(aa.begin(), aa.end(), Add(2,3));
for_each(ll.begin(), ll.end(), Add(z));
}
стр. 531
...
Это частный случай того правила, что, решая задачу, для достижения максимальной гибкости разумно использовать минимальный набор операций.
стр. 594
mea culpa -- "моя вина" (лат.)
стр. 615
И чтение, и запись производятся через итератор, разыменовываемый при помощи *:
*p = x; // запись x через p
x = *p; // считывание в x через p
... Независимо от своей категории, итератор может позволять как константный, так и неконстантный доступ к объекту, на который указывает. При помощи итератора на const вы не можете писать в элемент, к какой бы категории итератор не относился. Итератор обеспечивает набор операций, но окончательным судьёй, решающим, что можно сделать с элементом, является тип элементов, на которые указывает итератор.
При чтении и записи объекты копируются, поэтому типы элементов должны иметь обычную семантику копирования.
стр. 631
... опыт показывает, что для многих людей и многих прикладных программ доза паранойи не помешает -- особенно, когда в программу часто вносятся изменения несколькими людьми.
Один из способов проверки во время выполнения -- это держать в коде проверочные фрагменты. Затем, перед сдачей программы, они удаляются. Эту практику сравнивают с надеванием спасательного жилета при плавании вблизи берега и сниманием при выходе в открытое море
стр. 708
Если вы считаете, что C++ труден, попытайтесь выучить английский
стр. 792
Обширная и отличная аннотированная библиография (проектирование программных продуктов, проблемы менеджмента).
стр. 912
Преобразование из целого типа в тип с плавающей точкой настолько математически корректно, насколько позволяет аппаратура. Потеря точности происходит, если целочисленное значение нельзя точно представить типом с плавающей точкой. Например:
int i = float(1234567890);
Оставит i со значением 1234567936, если в машине и int, и float представляются 32 битами.
... Чтобы урезать число с гарантией переносимости, нужно воспользоваться numeric_limits.