Чистый синтаксис для изменения поведения инициализации статического члена - PullRequest
1 голос
/ 20 августа 2010

Я недавно читал, что Java теперь поддерживает блоки инициализации, подобные следующим:

class C {

    public C() { /* Instance Construction */ }
    static { /* Static Initialisation */ }
    { /* Instance Initialisation */ }

}

Меня особенно заинтересовал блок static. Это заставило меня задуматься о проблеме порядка статической инициализации, которая затрагивает многих начинающих пользователей C ++, и о типичных обходных путях ее решения, таких как упаковка статического члена в свободную функцию или использование расширения __attribute__((init_priority(n))) GNU.

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

Пока что это лучшее, что приходит на ум:

class C {
private:

    class Static {
    public:

        Static();

        int i;
        Foo foo;

    };

public:

    static Static statics;

    // ...

};

C::Static::Static() : i(42), foo("bar") {}

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

Проблема с этим, конечно, в том, что C::foo становится C::statics.foo, что довольно неестественно. Есть ли способ обойти неловкий синтаксис или есть лучшее решение в целом?

Ответы [ 2 ]

3 голосов
/ 20 августа 2010

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

Я вижу, как вам редко может понадобиться или вы хотите контролировать порядок статических инициализаций или по какой-то другой причине обернуть всю статику. Но с точки зрения читабельности, я предпочитаю проверенное:

class C
{
private:
  static int i;
  static Foo foo;
};

int C::i = 42;
Foo C::foo("bar");

Если у вас есть много таких статик, почему бы не отправить их всех в их собственный файл CPP? Но опять же, если у вас действительно так много статики, мне интересно, если что-то не так с общим дизайном, в первую очередь ...

0 голосов
/ 20 августа 2010

Чтобы было ясно, на самом деле есть три проблемы с глобальными переменными в целом (не только со статистикой):

  • Порядок инициализации Fiasco
  • Порядок уничтожения Fiasco
  • Многопоточность Несколько инициализаций

Конечно, в большинстве случаев уничтожение не является большой проблемой, но все же оно существует.

Новый C ++ 0xс поддержкой потоков, и, таким образом, есть некоторое преимущество (особенно для локальных статических переменных, связанных с многопоточностью).

С появлением C ++ 0x следующий код может пострадать только от "Разрушения"Закажите Fiasco "... если у вас нет циклической ссылки при инициализации курса.

// foo.h
class Foo
{
public:
  static Foo& Instance() { static Foo M; return M; }

private:
  Foo();
};

// bar.h
// idem for Bar

// foo.cpp
Foo::Foo() { Bar& bar = Bar::Instance(); .... }

Это прекрасно работает: поскольку экземпляр создается по требованию, язык гарантирует, что он будет там, когда вам это нужно,и с C ++ 0x гарантирует поведение, даже если несколько потоков пытаются получить доступ к функции одновременно.

Теперь, что из "Уничтожения Порядка Fiasco"?

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

Конечно,без C ++ 0x все немного сложнее.Чтобы избежать многопоточной проблемы, единственный совет - сначала обращаться ко всем переменным, пока приложение все еще однопоточное (в основном).Таким образом, создаются все экземпляры, и больше нет проблем с параллелизмом.

...