Книга ужасов "Effective Modern С++"

Scott Meyers "Effective Modern С++" (2016), в русском варианте Скотт Мейерс "Эффективный и современный С++". В процессе чтения обоих изданий: в дороге - epub с оригиналом на электрокнижке, на компьютере - PDF с переводом. Сюда буду кидать заметки по ходу.

Многостраничное предисловие, рассказывающее о том, как автор потел от усилий на спецфорумах, в конференциях usenet и на stackoverflow, чтобы понять "как эта хрень действительно работает", наводит на прямые аналогии с печальной историей эволюции языка PL/1. Си++ -- язык со сложной судьбой, непревзойденный чемпион по способам выстрелить себе в ногу, поэтому увеличить его страдания навешиванием новых фишек легко. И, похоже, основываясь на многочисленных "хотелках" и "интертрепациях" задач сообщества, дело пошло резво.

25 страниц посвящено описанию нового способа эффективно отстрелить себе пальцы -- использованию auto и выводу типов для auto и шаблонов. Двадцать пять, Карл! Зачем была вообще введена эта возможность? Оказывается, для облегчения переносимости типов и избавления от typedef. На протяжении многих страниц автор пытается сформулировать правила, по которым программист может попытаться угадать, какой же в действительности тип выведет компилятор.

Попутно автор сам того не желая пинает другое новшество -- инициализацию в фигурных скобочках.

auto x1 = 27; // Тип int, значение 27
auto x2(27);  // То же самое
auto x3 = {27}; // std::initializer_list<int>, значение { 27 }
auto x4{27};    // То же самое
// при этом
int x5{27};    // Тип int, значение 27
int x6 = {27}; // То же самое

Как правильно отмечено в книге, "эта ловушка является одной из причин, по которым некоторые разработчики используют фигурные скобки в инициализаторах только тогда, когда обязаны это делать". Иными словами, вменяемые программисты понимают, что новый синтаксис инициализации переменных -- очередной способ обделаться на ровном месте, поэтому не надо им пользоваться.

Синтез двух фишек, типа auto и инициализации, приводит к таким потрясающим эффектам. Очевидно, активисты, проталкивавшие в стандарт первую, не думали о второй и наоборот. При отсутствии архитектора, ушедшего читать лекции по Си++ первокурсникам техасского универа, получается как-то неудобно, да.

Не совсем понятно желание стандартизаторов превратить Си++ в этакий компилируемый в родной код Питон. Потому что для соответствующих задач нормальный программист просто возьмет Питон. С другой стороны, высокая популярность языка Си (без плюсов) говорит о том, что многие перестали видеть в новшествах смысл и предпочтут писать контролируемый софт на более простом и ясном языке даже поступившись объемом исходников и уровнем абстракций.

Следующая глава была посвящена вопросам сочетания инициализации фигурными скобочками с конструкторами, использующими initializer_list. Очередной способ прострелить себе ногу требует не только аккуратности, но и отслеживания изменений и расширений старого кода. В самом деле, если раньше у класса был, например, конструктор, принимающий два целых числа, то он использовался как в каноническом варианте со скобками, так и с фигурными.

class MyClass
{
public:
  MyClass() {}
  MyClass(int a, int b) {}
};
...
MyClass a(1, 2); // вызывает MyClass(int a, int b)
MyClass a{1, 2}; // то же самое

Но вот коллега Вася решил дописать классу конструктор с переменным числом целочисленных параметров (да, васины действия противоречат принципу проектирования "open-close", но и при наследовании проблема останется). И ба-бах! Старый код, где по каким-то причинам использовалась инициализация в фигурных скобках, перестал вызывать конструктор с двумя параметрами. Легким движением руки Вася захватил контроль.

class MyClass
{
public:
  MyClass() {}
  MyClass(int a, int b) {}
  MyClass(std::initializer_list<int> params) {}
};
...
MyClass a(1, 2); // вызывает MyClass(int a, int b)
MyClass a{1, 2}; // теперь вызывает MyClass(std::initializer_list

Мне даже пришлось написать более подробный тест-пример для уяснения тонкостей вызова конструкторов. Наверное, это тоже интересное занятие, если проект новый или другой работы нет.

Продолжение следует...