Интернет, компьютеры, софт и прочий Hi-Tech

Подписаться через RSS2Email.ru

Страница 8 из 10 - Предыдущая - Следующая
Все страницы - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10

Краткий FAQ по C++

[10.13] Как бороться с ошибками порядка статической инициализации объектов - членов класса?

Используйте ту же самую технику, которая описана в [10.12], но вместо глобальной функции используйте статическую функцию-член.

Предположим, у вас есть класс X, в котором есть статический объект Fred:

    // File X.hpp

    class X {
    public:
      // ...

    private:
      static Fred x_;
    };

Естественно, этот статический член инициализируется отдельно:

    // File X.cpp

    #include "X.hpp"

    Fred X::x_;

Опять же естественно, объект Fred будет использован в одном или нескольких методах класса X:

    void X::someMethod()
    {
      x_.goBowling();
    }

Проблема проявится, если кто-то где-то каким-либо образом вызовет этот метод, до того как объект Fred будет создан. Например, если кто-то создает статический объект X и вызывает его someMethod() во время статической инициализации, то ваша судьба всецело находится в руках компилятора, который либо создаст X::x_, до того как будет вызван someMethod(), либо же только после.

(Должен заметить, что ANSI/ISO комитет по C++ работает над этой проблемой, но компиляторы, которые работают в соответствии с последними изменениями, пока недоступны; возможно, в будущем в этом разделе будут сделаны дополнения в связи с изменившейся ситуацией.)

В любом случае, всегда можно сохранить переносимость (и это абсолютно безопасный метод), заменив статический член X::x_ на статическую функцию-член:

    // File X.hpp

    class X {
    public:
      // ...

    private:
      static Fred& x();
    };

Естественно, этот статический член инициализируется отдельно:

    // File X.cpp

    #include "X.hpp"

    Fred& X::x()
    {
      static Fred* ans = new Fred();
      return *ans;
    }

После чего вы просто меняете все x_ на x():

    void X::someMethod()
    {
      x().goBowling();
    }

Если для вас крайне важна скорость работы программы и вас беспокоит необходимость дополнительного вызова функции для каждого вызова X::someMethod(), то вы можете сделать static Fred&. Как вы помните, статические локальные переменные инициализируются только один раз (при первом прохождении программы через их объявление), так что X::x() теперь будет вызвана только один раз: во время первого вызова X::someMethod():

    void X::someMethod()
    {
      static Fred& x = X::x();
      x.goBowling();
    }

Примечание: ошибки статической инициализации не распространяются на базовые/встроенные типы, такие как int или char*. Например, если вы создаете статическую переменную типа float, у вас не будет проблем с порядком инициализации. Проблема возникает только тогда, когда у вашего статического или глобального объекта есть конструктор.

[10.14] Как мне обработать ошибку, которая произошла в конструкторе?

Сгенерируйте исключение. Смотрите подробности в [17.1].

Раздел [11]: Деструкторы

[11.1] Что такое деструктор?

Деструктор - это исполнение последней воли объекта.

Деструкторы используются для высвобождения занятых объектом ресурсов. Например, класс Lock может заблокировать ресурс для эксклюзивного использования, а его деструктор этот ресурс освободить. Но самый частый случай - это когда в конструкторе используется new, а в деструкторе - delete.

Деструктор это функция "готовься к смерти". Часто слово деструктор сокращается до dtor.

[11.2] В каком порядке вызываются деструкторы для локальных объектов?

В порядке обратном тому, в каком эти объекты создавались: первым создан - последним будет уничтожен.

В следующем примере деструктор для объекта b будет вызван первым, а только затем деструктор для объекта a:

    void userCode()
    {
      Fred a;
      Fred b;
      // ...
    }

[11.3] В каком порядке вызываются деструкторы для массивов объектов?

В порядке обратном созданию: первым создан - последним будет уничтожен.

В следующем примере порядок вызова деструкторов будет таким: a[9], a[8], ..., a[1], a[0]:

    void userCode()
    {
      Fred a[10];
      // ...
    }

Страница 8 из 10 - Предыдущая - Следующая

Биржа долевых инвестиций SIMEX.

Последнее редактирование: 2009-10-02 16:59:46

Метки материала: C++, FAQ, программирование, конструкторы, деструкторы, static initialization order, порядок инициализации, члены класса, функция, статические методы, комитет по C++, объект, dtor, объекты, глобальная функция, методы, статическая функция, инициализация

Оставьте, пожалуйста, свой комментарий к публикации

Представиться как     Антибот:
   

Просьба не постить мусор. Если вы хотите потестить xBB, воспользуйтесь кнопкой предварительного просмотра на панели инструментов xBBEditor-а.


© 2007-2019, Дмитрий Скоробогатов.
Разрешается воспроизводить, распространять и/или изменять материалы сайта
в соответствии с условиями GNU Free Documentation License,
версии 1.2 или любой более поздней версии, опубликованной FSF,
если только иное не указано в самих материалах.