C++ boost 在使用语言环境时崩溃

问题描述 投票:0回答:2

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

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

}

你能帮帮我吗?

问候, 提交

c++ boost crash locale
2个回答
10
投票

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

如果您只是对解决此问题的最直接方法感兴趣,那么将 Boost 构建为共享库应该可以做到。具体来说,我的意思是将 b2 命令行的

link
属性设置为
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 中。

替代方案

您可以使用 Boost 的静态库构建来执行此操作,方法是确保所有 DLL 中的所有

std::locale::facet
对象和使用 Boost.Locale 的可执行文件都安装到您尝试使用的
std::locale
对象中。

您可以使用如下代码来执行此操作。对于 DLL,当它的第二个参数

DllMain
fdwReason
时,您可以在
DLL_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
对象安装到全局语言环境中。


0
投票

这与我面临的问题相同。上面建议的解决方案(设置全局语言环境)没有用

© www.soinside.com 2019 - 2024. All rights reserved.