cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

Запрет на произвольный порядок записи инициализаторов в списках инициализации в конструкторах #95

Open Neargye opened 3 years ago

Neargye commented 3 years ago

Перенос предложения: голоса +23, -3 Автор идеи: Никита Колотов

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

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

15.6.2 [class.base.init] 13 In a non-delegating constructor, initialization proceeds in the following order: (13.1) First, and only for the constructor of the most derived class (6.6.2), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list. (13.2) Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers). (13.3) Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

На практике это может приводить ко следующим проблемам:

  1. Неопределенное Поведение непосредственно из-за использования неинициализированных полей:

    struct foo
    {
    foo(void)
    : frob{42}
    , zig{frob * 2} // frob is uninitialized at this point
    {}
    
    int zig;
    int frob;
    };
  2. промахи с порядком вызова функций с побочными эффектами, используемых при инициализации:
    
    int first(void);
    int second(void);

struct foo { foo(void) : frob{first()} , zig{second()} // second is called prior to first {}

int zig;
int frob;

};


В современных компиляторах уже достаточно давно реализованы диагностические сообщения на такой случай (-Wreorder). Соответственно я предлагаю добавить в стандарт требование однозначного соответствия следования инициализаторов в списке инициализации реальному порядку их вызова.
Neargye commented 3 years ago

zamazan4ik@tut.by 22 января 2020, 23:04 У Вас есть какие-то оценки о том, сколько кода сломается? :)

Никита Колотов 26 января 2020, 21:42 zamazan4ik@tut.by, Не так много. По большей части сломается только уже сломанный, неподдерживаемый код, в первую очередь старые проекты под Visual Studuo, в которой до недавнего времени диагностика такого рода проблем ограничивалась обнаружением использования неинициализированных переменных. Проекты под g++ и clang++ собираемые хотя бы с минимальным уровнем предупреждений -Wall (в который входит -Wreorder) по идее не должны потребовать правок. Осознание сложностей с неправильным порядком инициализаторов пришло достаточно давно - диагностика Wreorder появилась более 10 лет назад, так что данное предложение по сути просто попытка закрепить устоявшуюся практику.

Alexander 27 января 2020, 13:29 Никита Колотов, я это понимаю. Но навскиду и я могу говорить. Я более чем уверен, что есть куча кодовой базы, которая собирается без этого варнинга\забивает на него. Поэтому это может отломать работающий нормально код.

Если приведёте статистику, которую вы соберёте хотя бы по Open Source проектам, к своему предложению, будет превосходно. Если что, могу дать отправную точку, как это делать :)

Никита Колотов 27 января 2020, 22:58 Alexander, Скажем так, проекты, которые не задают при сборке даже минимального уровня предупреждений (то бишь даже без -Wall), я бы не стал характеризовать как "работающий нормально код". Статистику собрать было бы конечно хорошо, но как собрать достаточно объемную достоверную статистику - это вопрос. Первое, что приходит в голову - поискать на гитхабе: поиск [c++] -Wall дает 11М+ результатов по коду 1M по коммитам, а -Wno-reorder только 36К по коду и только 625 коммитов.

webreh 19 февраля 2020, 9:44 Для начало надо это deprecate, и никакой код не сломается.