Почему исключение std :: bad_cast в boost :: locale :: date_time для глобальных, но не локальных объектов? - PullRequest
1 голос
/ 22 апреля 2020

У меня проблемы с написанием класса-оболочки с использованием библиотеки boost :: locale :: date_time. В частности, я не могу создать глобальный объект из своего класса, хотя все отлично работает, кроме этого.

Вот соответствующий пример кода:

// DateTimeWrapper.h

#include <boost\\locale\\date_time.hpp>
#include <boost\\locale.hpp>

class DateTimeWrapper
{
public:
    DateTimeWrapper();
    ~DateTimeWrapper();

    // ... Other methods...

protected:

    boost::locale::date_time* m_date_time;
    static void Init_Global_Locale();
    static bool m_Global_Locale_Initialized;
};
// DateTimeWrapper.cpp

bool DateTimeWrapper::m_Global_Locale_Initialized = false;

DateTimeWrapper::DateTimeWrapper()
{
    Init_Global_Locale();

    // The following line will work for the local object,
    // but throws a std::bad_cast exception for the global object
    m_date_time = new boost::locale::date_time;
}

DateTimeWrapper::~DateTimeWrapper()
{
    delete m_date_time;
}

void DateTimeWrapper::Init_Global_Locale()
{
    if (!m_Global_Locale_Initialized)
    {
        boost::locale::generator gen;
        std::locale l = gen("");
        std::locale::global(l);

        m_Global_Locale_Initialized = true;
    }
}

// This object throws a std::bad_cast exception.  Code runs normally if I comment out the following line.
DateTimeWrapper global_date_time_object;

int main()
{
    // This object works just fine
    DateTimeWrapper local_date_time_object;

    // Do stuff with local_date_time_object...

    return(0);
}

Как вы можете видеть в коде Я использую элемент stati c, чтобы убедиться, что глобальная локаль инициализируется при первом создании объекта DateTimeWrapper. Обычно это предотвращает появление исключения std :: bad_cast при создании моего члена boost :: locale :: date_time. Однако я по-прежнему получаю исключение из этой строки, когда первый созданный объект DateTimeWrapper является глобальным экземпляром.

Обратите внимание, что, проходя через отладчик, я могу подтвердить, что все строки в методе Init_Global_Locale () выполняются во время построения глобального объекта. В этом примере кода также объявляется DateTimeWrapper :: m_Global_Locale_Initialized до того, как он объявляет global_date_time_object, в том же исходном файле, поэтому я знаю, что порядок инициализации здесь не является проблемой (подтверждается, если все равно пройти через отладчик).

Так почему же код работает для локальных объектов, но не для глобальных объектов, хотя я вижу, что все строки кода проходят в правильном порядке для обеих версий?

1 Ответ

0 голосов
/ 22 апреля 2020

Я не могу воспроизвести ошибку (с кодом, показанным в одном TU).

Я догадываюсь, что у вас есть void DateTimeWrapper::Init_Global_Locale() и m_Global_Locale_Initialized, определенные в другой единице перевода, что приводит вас к SIOF (stati c фиаско порядка инициализации).

Кроме того, существуют многочисленные сложности с ошибками приглашения типов для ваших типов (использование не принадлежащих указателям указателей, а не следование Rule-Of-Zero) / Три / Five ). Я написал бы это намного проще, используя локальную функцию инициализации функции C ++ 11 c:

#include <boost/locale.hpp>
#include <boost/locale/date_time.hpp>

struct EnsureLocaleBase {
    EnsureLocaleBase() { Init(); }

  private:
    static bool Init() {
        static auto const s_init = [] {
            boost::locale::generator gen;
            std::locale l = gen("");
            std::locale::global(l);
            return true;
        }();
        return s_init;
    }
};

class DateTimeWrapper : EnsureLocaleBase {
    boost::locale::date_time m_date_time;
};

DateTimeWrapper global_date_time_object;

int main() {
    DateTimeWrapper local_date_time_object;
}

Статические функции локальных функций не страдают SIOF и также инициализируются потокобезопасными.

...