Однажды я прочитал замечательный FAQ по C ++ (это действительно хорошо !!) и прочитал тема о том, как предотвратить" фиаско "статического порядка инициализации. Поэтому автор советует обернуть статические переменные в функции, чтобы предотвратить «фиаско», сохранив порядок создания переменных. Но мне кажется, что это грубый обходной путь. Итак, мой вопрос: есть ли какой-нибудь современный, более ориентированный на шаблоны способ предотвратить это "фиаско", кроме как обернуть "статический материал" в функции ???
Предотвращение фиаско с порядком статической инициализации, C ++
Ответы (3)
Современный, более ориентированный на шаблоны способ - это вообще не использовать глобальные переменные.
Другого пути нет.
Иначе это не было бы большим фиаско!
Итак, мой вопрос: есть ли какой-нибудь современный, более ориентированный на шаблоны способ предотвратить это "фиаско", кроме как обернуть "статический материал" в функции ???
В большинстве случаев вы можете объявить свои «глобальные» данные в основной функции и использовать внедрение зависимостей для их передачи там, где это необходимо. Другими словами, вообще не иметь статического состояния.
На практике могут возникнуть ситуации, когда требуются статические данные. Если нет зависимостей от других статик, сделайте статические данные const/constexpr
.
// smart pointer that implements the "Foo" release policy
class FooPointer
{
static const FooPointer NullFoo; // does not depend on other static values
/* ... */
};
Если статические переменные действительно зависят друг от друга, просто оберните их в статические функции:
// smart pointer that implements the "Foo" release policy
class FooPointer
{
static const FooPointer& NullFoo(); // depends on other static values
/* ... */
};
Обобщить:
Большинство (90% - 99%?) Статических / глобальных / общих данных должны вводиться в зависимости от того, где они используются, а не создаваться как статические вообще.
В редких случаях, когда статика требуется по той или иной причине и она не зависит от другой статики, объявляйте статические переменные.
В очень редких случаях, когда статики должны быть статическими и они зависят друг от друга, используйте их в статических методах.
Как показывает практика, если у вас много второго и третьего случаев, вы не делаете достаточно первого.
Более обычный способ решения проблемы - избегать статики, когда это возможно, и тем более между объектами, которые зависят от порядка построения.
Затем постройте объекты в нужном порядке. Например, если у нас есть два объекта x и y, и построение y завершится неудачно, если x не был построен, сначала создайте x и передайте его конструктору (или другому члену) y)
SomeObject x;
SomeOtherObject y(x);
or
SomeObject *x = new SomeObject;
SomeOtherObject y = new SomeObject(*x);
(оба из вышеперечисленных предполагают, что конструктору y
требуется ссылка).
Если вам нужно разделить x
и y
между функциями, просто передайте их функциям в качестве аргументов.
Если вы должны использовать статику (т.е. вы не хотите, чтобы вводились передаваемые аргументы повсюду), сделайте статику указателями и инициализируйте их один раз (например, в main()
).
// all source files can use x and y via these declarations (e.g. via a header file)
extern SomeObject *x;
extern SomeOtherObject *y;
// definition in one source file only
SomeObject *x;
SomeOtherObject *y;
int main()
{
x = new SomeObject;
y = new SomeOtherObject(*x);
// call other functions that use x and y.
delete y;
delete x;
}
Но на самом деле лучше избегать использования статики, если это вообще возможно.