【问题标题】:Why std::bad_cast exception in boost::locale::date_time for global but not local objects?为什么 boost::locale::date_time 中的 std::bad_cast 异常适用于全局对象而不是本地对象?
【发布时间】:2020-08-05 09:23:25
【问题描述】:

我在使用 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,所以我知道这里的初始化顺序不是问题(通过调试器逐步确认)。

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

【问题讨论】:

  • #include &lt;boost\\locale\\date_time.hpp&gt; 应该是 #include &lt;boost/locale/date_time.hpp&gt;,另一个也是如此
  • offtopic:在 include 中始终使用 unix 样式的目录分隔符 /。 VS 在没有警告的情况下正确处理。
  • 上面的代码在我的机器上工作(在修复了斜杠之后)。我确实必须在我的编译行上添加-lboost_system-mt -lboost_locale-mt(我编译为-std=c++17,使用Boost 1.72)。
  • @MarekR 我有一个只包含静态方法的助手类。其中一种方法使用静态的、固定的历史日期——我将其声明为助手类的静态成员。如果不是作为静态(即全局)成员变量,那么定义和使用此日期的更好方法是什么?我看到的唯一选择是每次调用静态方法时都在静态方法中创建本地版本的日期,这不仅效率低,而且比我想要的更不透明(该日期将被埋在函数内部而不是在文件的顶部,很容易看到或调整)。

标签: c++ boost global boost-date-time boost-locale


【解决方案1】:

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

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

此外,您的类型引发错误有很多复杂性(使用非拥有指针,而不是遵循Rule-Of-Zero/Three/Five)。我会写得更简单,使用 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 的影响,并且是线程安全初始化的。

【讨论】:

    猜你喜欢
    • 2012-10-19
    • 2017-12-02
    • 2023-03-28
    • 2010-10-29
    • 2016-07-08
    • 1970-01-01
    • 2012-10-25
    • 1970-01-01
    相关资源
    最近更新 更多