使用locale时C++ boost崩溃

use*_*291 5 c++ crash boost locale

我正在尝试使用boost库为我的字符串类提供i18支持.我使用的是Microsoft Visual Studio编译器VC10和64位Windows 7机器.

我能够使用boost库编译和链接我的应用程序,但是我的应用程序在调用boost :: locale :: to_upper()时崩溃了.

以下是我写的代码.

#include <boost/locale.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/system/config.hpp>



 String::MakeUpper()()
    {
    boost::locale::generator gen;
    std::locale loc = gen("");
    std::locale::global(loc);
    std::string str2 = boost::locale::to_upper("001Öä", loc); // application crashes here.
    std::string str3 = boost::locale::to_upper("001Öä"); // This also does not work
    }
Run Code Online (Sandbox Code Playgroud)

崩溃发生在以下函数中.此函数抛出错误的强制转换异常.

template<class _Facet> inline
const _Facet& __CRTDECL use_facet(const locale& _Loc)

{   // get facet reference from locale
_BEGIN_LOCK(_LOCK_LOCALE)   // the thread lock, make get atomic
    const locale::facet *_Psave =
        _Facetptr<_Facet>::_Psave;  // static pointer to lazy facet

    size_t _Id = _Facet::id;
    const locale::facet *_Pf = _Loc._Getfacet(_Id);

    if (_Pf != 0)
        ;   // got facet from locale
    else if (_Psave != 0)
        _Pf = _Psave;   // lazy facet already allocated
    else if (_Facet::_Getcat(&_Psave, &_Loc) == (size_t)(-1))

#if _HAS_EXCEPTIONS

        _THROW_NCEE(bad_cast, _EMPTY_ARGUMENT); // lazy disallowed

....
....
....

}
Run Code Online (Sandbox Code Playgroud)

你能帮帮我吗?

此致,Sumit

小智 10

在Windows 7 64位上的Visual Studio 2008应用程序中使用Boost 1.55的静态库构建时,我遇到了同样的问题,其中主要可执行文件和几个DLL都链接到Boost.我不确定你的问题是否与我的相同,因为你没有提到使用DLL,但当我第一次开始调查时,这并不是我认为相关的东西.

如果您只是对最直接的解决方法感兴趣,那么将Boost构建为共享库就应该这样做.具体来说,我的意思link是将b2命令行的属性设置为shared而不是static.

说明

使用静态库构建的原因有一个问题是由于Boost.Locale使用std::locale::facet对象进行文本转换操作,如上限和规范化. std::locale::facet类需要有一个id静态成员变量,其标准库实现在静态初始化期间构造时,其唯一值由其赋值.

使用静态库时的问题是,所有可执行文件和DLL都从静态库中获取自己的静态成员变量的不同副本,如C++静态库中的共享全局变量中所述.当您用于boost::locale::generator::operator()生成语言环境时,它仅将std::locale::facet对象安装到具有id成员变量的语言环境中,该成员变量是包含该调用的同一DLL或可执行文件的一部分.

正如我上面所说,解决这个问题最直接的方法是将Boost构建为共享库.那样只会有一个副本Boost.Locale的静态成员变量.具体来说,它们将位于Boost.Locale DLL中.

替代方案

您可以通过确保std::locale::facet所有DLL中的所有对象和使用Boost.Locale的可执行文件安装到std::locale您尝试使用的对象中来构建Boost的静态库.

您可以使用下面的代码来执行此操作.对于DLL,你可以在调用这个DllMain时候它的第二个参数fdwReasonDLL_PROCESS_ATTACH,和你的可执行文件,你可以把它在WinMain或其他一些应用程序入口点(如果你使用像MFC或QT).

void setup_global_locale()
{
    const boost::locale::generator generator;
    const std::locale locale = generator.generate( std::locale(), "" );
    std::locale::global( locale );
}
Run Code Online (Sandbox Code Playgroud)

代码的重要部分是它每次运行时都使用全局语言环境作为基本语言环境,并将新生成的语言环境安装为新的全局语言环境.这与boost::locale::generator::operator()将要做的不同,因为它std::locale::classic用作基本语言环境,并且无法修改.通过从每个DLL和可执行文件中调用它,您将其每个std::locale::facet对象安装到全局区域设置中.