Статическая инициализация в C++

Всем привет!

Я разрабатываю приложение winForm на визуальном C++ (управляемый код). Это приложение связывает собственную статическую библиотеку, содержащую блок кода с инициализацией статической переменной:

Клс.ч

class Cls
{
public:
    static Cls* getInstance();

private:
    static Cls _instance;
protected:
    Cls(void);
};

Cls.cpp

#include "StdAfx.h"
#include "Cls.h"

Cls::Cls(void)
{
}

Cls Cls::_instance;

Cls* Cls::getInstance()
{
    return &_instance;
}

Я могу успешно связать эту библиотеку, но когда я пытаюсь использовать метод getInstance(), я получаю ошибку времени выполнения перед вызовом основной функции моего приложения.

Это сторонняя библиотека, поэтому я не могу перестроить ее или переопределить класс Cls каким-либо другим способом.

В проекте приложения используется /clr, точка входа определена как main.

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

Пожалуйста помоги!


person user1514958    schedule 10.07.2012    source источник
comment
Я бы предложил попробовать и посмотреть, верно ли значение, вместо того, чтобы строить догадки о том, что значение может быть неверным.   -  person Vite Falcon    schedule 10.07.2012
comment
В какой момент вы звоните getInstance()? Во время инициализации или позже?   -  person Fiktik    schedule 10.07.2012


Ответы (1)


Вы столкнулись с пресловутым "фиаско порядка статической инициализации". Когда статические объекты определены в двух единицах перевода, не указано, какая из них инициализируется первой; поэтому, если конструктор одного ссылается на другой, вы можете получить к нему доступ до его инициализации. Единственная гарантия состоит в том, что все они будут инициализированы до начала main.

Лучшее решение — избегать статических объектов. В частности, анти-шаблон Singleton, который вы используете, довольно сложно правильно реализовать в C++, и, как правило, он приносит больше проблем, чем пользы.

Если вы действительно хотите это сделать, вы можете обойти фиаско, определив статический объект внутри функции:

Cls* Cls::getInstance()
{
    static Cls _instance;
    return &_instance;
}

Недостаток этого состоит в том, что он вводит «фиаско порядка уничтожения» (где доступ из деструктора другого статического объекта может быть небезопасным) и что он может быть не потокобезопасным в некоторых компиляторах (хотя он должен быть в любом который заявляет о соответствии C++11). Если конструкция является потокобезопасной, то для каждого доступа будут (небольшие) затраты времени выполнения, что может быть проблемой, если у вас есть экстремальные проблемы с производительностью.

ОБНОВЛЕНИЕ: я только что заметил, что вы говорите, что этот злой класс находится вне вашего контроля и не может быть изменен. В этом случае ваши варианты:

  • Избавьтесь от этой библиотеки и используйте что-то менее безумное, или
  • Будьте осторожны, чтобы не получить доступ к каким-либо его статическим данным до тех пор, пока не начнется main; в частности, следуйте моему совету выше и избегайте собственных статических объектов.
person Mike Seymour    schedule 10.07.2012
comment
Разве это не должно быть static Cls _instance;? - person Archie; 10.07.2012
comment
@Fiktik: Спасибо, я этого не заметил. В этом случае возможности ограничены. - person Mike Seymour; 10.07.2012