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
.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With