1

我在使用 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);
}

正如您在代码中看到的,我使用静态成员来确保在第一次创建 DateTimeWrapper 对象时初始化全局语言环境。通常,这可以防止在我创建 boost::locale::date_time 成员时引发 std::bad_cast 异常。但是,当创建的第一个 DateTimeWrapper 对象是全局实例时,我仍然从该行收到异常。

请注意,通过调试器,我可以确认 Init_Global_Locale() 方法中的所有行都在构建全局对象期间运行。此示例代码还在同一个源文件中声明 global_date_time_object 之前声明了 DateTimeWrapper::m_Global_Locale_Initialized,因此我知道这里的初始化顺序不是问题(无论如何通过调试器进行确认)。

那么为什么代码适用于本地对象而不适用于全局对象,即使我可以看到所有代码行都以正确的顺序运行,对于两个版本?

4

1 回答 1

0

我无法重现错误(使用单个 TU 中显示的代码)。

我的预感是您在另一个翻译单元中有 voidDateTimeWrapper::Init_Global_Locale()m_Global_Locale_Initialized定义,这使您陷入SIOF(静态初始化顺序惨败)。

此外,您的类型引发错误有许多复杂性(使用非拥有指针,不遵循零/三/五规则)。我会写得更简单,使用 C++11 的函数本地静态初始化:

#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 的影响,并且是线程安全初始化的。

于 2020-04-22T14:23:51.480 回答