使用区域设置时C ++ Boost崩溃 [英] C++ boost crashes while using locale

查看:111
本文介绍了使用区域设置时C ++ Boost崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用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
    }

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

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

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

}

能请你帮我吗?

关于, 提交

解决方案

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

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

说明

使用静态库构建的原因是由于使用 C ++静态库中的共享全局变量.当您使用boost::locale::generator::operator()生成语言环境时,只会将std::locale::facet对象安装到具有id成员变量的语言环境中,该成员变量是包含该调用的相同DLL或可执行文件的一部分.

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

替代解决方案

您可以使用Boost的静态库构建来实现此目的,方法是确保所有DLL中的所有std::locale::facet对象以及使用Boost.Locale的可执行文件都已安装到您要使用的std::locale对象中.

您可以使用以下类似的代码来执行此操作.对于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 );
}

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

I am trying to use boost library for providing i18 support to my string class. I am using Microsoft Visual studio compiler VC10 and 64 bit Windows 7 machine.

I am able to compile and link my application with the boost library however my application crashes while invoking boost::locale::to_upper().

Following is the code I wrote.

#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
    }

The crash happens in the following function. this function throws bad cast exception.

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

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

}

Could you please help me out.

Regards, Sumit

解决方案

I had this same issue when using a static library build of Boost 1.55 in a Visual Studio 2008 application on Windows 7 64-bit where both the main executable and a couple DLLs all linked to Boost. I'm not sure if your issue is the same as mine since you didn't mention using DLLs, but that wasn't something I thought was relevant when I first started investigating this.

If you're just interested in the most straight-forward way to fix this, then building Boost as a shared library should do it. Specifically, I mean setting the link property of the b2 command-line to shared rather than static.

Explanation

The reason using a static library build has a problem is due to Boost.Locale using std::locale::facet objects for doing its text conversion operations like upper-casing and normalizing. std::locale::facet classes are required to have an id static member variable whose unique value is assigned by the Standard Library implementation when it is constructed during static initialization.

The problem with this when using a static library is that all executables and DLLs get their own distinct copy of static member variables from a static library, as discussed in Shared global variable in C++ static library. When you use boost::locale::generator::operator() to generate a locale, it only installs the std::locale::facet objects into the locale that have an id member variable that is part of the same DLL or executable where that call is contained.

As I said above, the most straight-forward way to fix this is to build Boost as a shared library. That way there will only be one copy Boost.Locale's static member variables. Specifically, they'll be in the Boost.Locale DLL.

Alternative Solution

You can do this with a static library build of Boost by making sure all of std::locale::facet objects from all DLLs and the executable using Boost.Locale get installed into the std::locale object you're trying to use.

You can use some code like below to do this. For DLLs, you could call this in DllMain when its second parameter fdwReason is DLL_PROCESS_ATTACH, and for your executable, you could call it in WinMain or some other application entry point (if you're using something like MFC or Qt).

void setup_global_locale()
{
    const boost::locale::generator generator;
    const std::locale locale = generator.generate( std::locale(), "" );
    std::locale::global( locale );
}

The important piece of the code is that it's using the global locale as the base locale each time it's run, and it installs the newly-generated locale as the new global locale. This is different from what boost::locale::generator::operator() will do, since it uses std::locale::classic as the base locale, and that one cannot be modified. By calling this from each DLL and the executable, you'll install each of their std::locale::facet objects into the global locale.

这篇关于使用区域设置时C ++ Boost崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆