TLDR; static (const) переменные в global scope работяют как в Си, в local scope создаётся туча кода с мьтексами, блокировками и бросанием исключений.
Снова и снова я возвращаюсь к С++ с мыслями "ну, может не такой он и стрёмный? в конце-концов RAII, можно красиво писать" и каждый раз какое-то говно находится. В этот раз — https://manishearth.github.io/blog/2015/06/26/adventures-in-systems-programming-c-plus-plus-local-statics/. А что там было насчёт "не плати за то, что не используешь?", а что насчёт move semantics и precondition? Почему тут нельзя было так же сделать: объявил локально статичную переменную — будь добр не вызывать эту функцию абы как?
Здравствуйте, mbait, Вы писали:
M>Почему тут нельзя было так же сделать: объявил локально статичную переменную — будь добр не вызывать эту функцию абы как?
Так и было до C++11, в котором появились т.н. magic statics. Если не хотите платить за эту магию, используйте C++03 и/или обычные глобальные статические переменные в C++11+.
Здравствуйте, mbait, Вы писали:
M>Почему тут нельзя было так же сделать: объявил локально статичную переменную — будь добр не вызывать эту функцию абы как?
Хорошая реализация имеет минимальный оверхед.
Если так уж нужна не-потокобезопасная инциализация, можно это дело провернуть ну хотя бы так
{
static std::optional<X> x; // не будет безопасной ленивой инициализации, т.к. конструктор constexprif (!x) x.emplace(...); // небезопасная ленивая инициализация
}
Но в целом, она скорее не нужна, чем нужна.
Многопоточность может потребоваться там, где её совсем не ждали.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, mbait, Вы писали:
M>>Почему тут нельзя было так же сделать: объявил локально статичную переменную — будь добр не вызывать эту функцию абы как?
AG>Хорошая реализация имеет минимальный оверхед.
AG>Если так уж нужна не-потокобезопасная инциализация, можно это дело провернуть ну хотя бы так AG>
AG>{
AG> static std::optional<X> x; // не будет безопасной ленивой инициализации, т.к. конструктор constexpr
AG> if (!x) x.emplace(...); // небезопасная ленивая инициализация
AG>}
AG>
AG>Но в целом, она скорее не нужна, чем нужна. AG>Многопоточность может потребоваться там, где её совсем не ждали.
У меня больше был вопрос: почему нельзя выполнять инициализацию до вызова main? Тогда и обвязка бы не понадобилась. Или хотя бы сделать так, если одновременно и static, и const?
M>У меня больше был вопрос: почему нельзя выполнять инициализацию до вызова main? Тогда и обвязка бы не понадобилась.
А, ну такая семантика уже не в С++11 появилось, а в старом С++, когда ещё не требовалась потокобезопасность.
Она востребована, например, многие слышали про "синглтон Мейерса".
С не-ленивой инициализацией до main можно столкнуться со следующими проблемами:
1. Порядок инициализации, зависимости между этими статическими объектами
2. О ужас, у нас может быть многопоточность уже до main
3. Нужны параметры, которые приходят только при вызове функции
M>Или хотя бы сделать так, если одновременно и static, и const?
Если там совсем constexpr, то так оно и будет. А const толком ничего не гарантирует.
Здравствуйте, Constructor, Вы писали:
C>Так и было до C++11, в котором появились т.н. magic statics. Если не хотите платить за эту магию, используйте C++03 и/или обычные глобальные статические переменные в C++11+.
GCC и в C++03 инициализирует потокобезопасно. Насчет VC++ не уверен, но вроде тоже.
Здравствуйте, mbait, Вы писали:
M>TLDR; static (const) переменные в global scope работяют как в Си, в local scope создаётся туча кода с мьтексами, блокировками и бросанием исключений.
Локальные статики нужны, если хочется не конструировать объект, если не используешь (то самое "не плати"), и/или параметры для конструирования приходят в функцию аргументами и/или хочется иметь контроль за очередностью инициализации.
Если тебе все это не нужно, не используй локальные статики, в чем проблема-то?
Если не хотите платить за эту магию, используйте C++03 и/или обычные глобальные статические переменные в C++11+.
Для начала хорошо бы разобраться, как именно вы платите. Во всех известных мне современных архитектурах после первоначальной инициализации плата — это один бранч, который предсказывается правильно с третьего раза. Так что разговор о платетя считаю неуместным.
Здравствуйте, andrey.desman, Вы писали:
AD>Локальные статики нужны, если хочется не конструировать объект, если не используешь (то самое "не плати"), и/или параметры для конструирования приходят в функцию аргументами и/или хочется иметь контроль за очередностью инициализации. AD>Если тебе все это не нужно, не используй локальные статики, в чем проблема-то?
В Си локальные статики это один из приёмов сохранения области имён чистой с одновременной оптимизацией кода. Правда, стоит отметить, что всё, что можно объявить в Си static const, можно объявить в C++ static constexpr, и тогда вспомогательный код не будет сгенерирован.
Здравствуйте, mbait, Вы писали:
M>В Си локальные статики это один из приёмов сохранения области имён чистой с одновременной оптимизацией кода. Правда, стоит отметить, что всё, что можно объявить в Си static const, можно объявить в C++ static constexpr, и тогда вспомогательный код не будет сгенерирован.
Все, что в Си можно объявить static const, в С++ можно так же объявить static const и тоже без вспомогательного кода, потому что pod.
Здравствуйте, mbait, Вы писали:
M>У меня больше был вопрос: почему нельзя выполнять инициализацию до вызова main? Тогда и обвязка бы не понадобилась. Или хотя бы сделать так, если одновременно и static, и const?
Сильно легче бы не стало, потому что конструкторы этих переменных могут обращаться к другим подобным переменным, порождать потоки и всякое такое.
Отлаживаться было бы очень эротично: программа еще до main'а не дошла, а в ней уже непонятно, что происходит