Question about boost::locale translations
Hi everybody! :) I’m currently trying to replace libintl (from gnu gettext) by boost::locale lib, in a (mostly) C program (blender, actually). To do so, I wrote a simplistic wrapper: #include <boost/locale.hpp> #include "boost_locale_wrapper.h" static boost::locale::generator gen; /* Called only once */ void boost_locale_init(const char *messages_path, const char *default_domain) { gen.add_messages_path(messages_path); gen.add_messages_domain(default_domain); gen.set_default_messages_domain(default_domain); } /* Called each time you change locale */ void boost_locale_set(const char *locale) { if (locale && locale[0]) { std::locale::global(gen(locale)); } else { std::locale::global(gen("")); } } const char* boost_locale_gettext(const char *msgid) { return boost::locale::gettext(msgid).c_str(); } (this wrapper lib is linked statically with the main app) But I'm facing a big problem: I would expect strings returned by boost::locale::gettext & co to be "const", i.e. that the char pointer gotten by boost::locale::gettext(msgid).c_str() would be const (and unique to a given locale/msgid/context/etc.), as it is with gnu gettext. But this is obviously not the case, as demonstrated by those prints (translated_msgid (address)): Serbe latin (Srpski latinica) (0x7fcaed0dac58) sr_RS@latin (0x7fcaee1e5628) Suédois (Svenska) (0x7fcaed0dac58) sv_SE (0x7fcaee1e5628) Am I missing something obvious here, or are returned string just not "const"? If so, how can a code like: MessageBoxW(0,pgettext <http://www.boost.org/doc/libs/1_49_0/libs/locale/doc/html/group__message.html#ga2a39910bdf57e4d151607ee1a115b853>(L"File Dialog",L"Open?").c_str(),gettext <http://www.boost.org/doc/libs/1_49_0/libs/locale/doc/html/group__message.html#gadd3006a6d5d1c804490152ee6300d47f>(L"Question").c_str(),MB_YESNO); (taken from boost doc) could work? I'm quite new to all this C++2C stuff (and to boost too), so please forgive me if this is a noob question... Best regards, Bastien
On Mon, Nov 5, 2012 at 7:19 PM, Bastien Montagne <montagne29@wanadoo.fr>wrote:
const char* boost_locale_gettext(const char *msgid) { return boost::locale::gettext(msgid).**c_str(); }
The line above decomposes so: 1) std::string hidden_tmp1 = boost::locale::gettext(msgid) 2) const char* hidden_tmp2 = hidden_tmp1.**c_str() // get pointer to internal buffer 3) ; // delete hidden_tmp1, which frees buffer hidden_tmp2 points to. Temporaries live until the semi-colon. 4) return hidden_tmp2 // pointer to freed (stale) memory. Not good.
I'm quite new to all this C++2C stuff (and to boost too), so please forgive me if this is a noob question...
You need to strdup() the c_str(), return a pointer to that, *and* document that callers are responsible for freeing the memory returned to them. Or your wrapper keeps track of this memory itself somehow, and releases down the line somehow again, so the callers do not need to explicitly free those strings. --DD
I suspected something like that (and indeed it worked with a strdup). Unfortunately, I’m not sure there will be a nice and suitable way to handle this, will try to find something… Anyway, thank you very much for the answer! :) On 06/11/2012 10:28, Dominique Devienne wrote:
On Mon, Nov 5, 2012 at 7:19 PM, Bastien Montagne <montagne29@wanadoo.fr <mailto:montagne29@wanadoo.fr>> wrote:
const char* boost_locale_gettext(const char *msgid) { return boost::locale::gettext(msgid).c_str(); }
The line above decomposes so:
1) std::string hidden_tmp1 = boost::locale::gettext(msgid) 2) const char* hidden_tmp2 = hidden_tmp1.c_str() // get pointer to internal buffer 3) ; // delete hidden_tmp1, which frees buffer hidden_tmp2 points to. Temporaries live until the semi-colon. 4) return hidden_tmp2 // pointer to freed (stale) memory. Not good.
I'm quite new to all this C++2C stuff (and to boost too), so please forgive me if this is a noob question...
You need to strdup() the c_str(), return a pointer to that, *and* document that callers are responsible for freeing the memory returned to them. Or your wrapper keeps track of this memory itself somehow, and releases down the line somehow again, so the callers do not need to explicitly free those strings. --DD
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
You can use message_format facet directly http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/group__message.htm... i.e. char const *gettext(char const *input) { try { std::locale l; boost::locale::message_facet<char> const &facet = std::use_facet<boost::locale::message_facet<char> >(l); char const *r = facet.get(my_domain_id,0,input); if(r) return r; return input; } catch(std::exception const &e) { return input; } } Note the input must have the SAME encoding as the locale. Artyom Beilis -------------- CppCMS - C++ Web Framework: http://cppcms.com/ CppDB - C++ SQL Connectivity: http://cppcms.com/sql/cppdb/
________________________________ From: Bastien Montagne <montagne29@wanadoo.fr> To: boost-users@lists.boost.org Sent: Tuesday, November 6, 2012 11:42 AM Subject: Re: [Boost-users] Question about boost::locale translations
I suspected something like that (and indeed it worked with a strdup). Unfortunately, I’m not sure there will be a nice and suitable way to handle this, will try to find something…
Anyway, thank you very much for the answer! :)
On 06/11/2012 10:28, Dominique Devienne wrote: On Mon, Nov 5, 2012 at 7:19 PM, Bastien Montagne <montagne29@wanadoo.fr> wrote:
const char* boost_locale_gettext(const char *msgid)
{ return boost::locale::gettext(msgid).c_str(); }
The line above decomposes so:
1) std::string hidden_tmp1 = boost::locale::gettext(msgid) 2) const char* hidden_tmp2 = hidden_tmp1.c_str() // get pointer to internal buffer 3) ; // delete hidden_tmp1, which frees buffer hidden_tmp2 points to. Temporaries live until the semi-colon.
4) return hidden_tmp2 // pointer to freed (stale) memory. Not good. I'm quite new to all this C++2C stuff (and to boost too), so please forgive me if this is a noob question...
You need to strdup() the c_str(), return a pointer to that, *and* document that callers are responsible for freeing the memory returned to them. Or your wrapper keeps track of this memory itself somehow, and releases down the line somehow again, so the callers do not need to explicitly free those strings. --DD
_______________________________________________
Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Tue, Nov 6, 2012 at 11:11 AM, Artyom Beilis <artyomtnk@yahoo.com> wrote:
You can use message_format facet directly [...] char const *gettext(char const *input) { try { std::locale l; boost::locale::message_facet<char> const &facet = std::use_facet<boost::locale::message_facet<char> >(l); char const *r = facet.get(my_domain_id,0,input); if(r) return r; return input; } [...] }
Much better. But who exactly is in charge of the lifetime of the returned r pointer? And when does the memory get released exactly (if ever)? Just curious. The API doc you linked to doesn't say. Is there a higher-level doc that discussed memory management of those translated C strings? TIA, --DD
Thank you very much, Artyom, it's exactly what I was looking for, works like a charm! :D Much better than my previous hack (which was simply storing the last translated messages's std::basic_string in a static array with "rotating" index). @Dominique: I'm of course no reference at all here, but I'd say (or guess) it's returning pointer to the internal representation of the messages for the current mo file, hence that memory would be freed when "unloading" that (locale/domain(/encoding?)-dependent) catalog (and pointer is valid until then)... On 06/11/2012 11:46, Dominique Devienne wrote:
On Tue, Nov 6, 2012 at 11:11 AM, Artyom Beilis<artyomtnk@yahoo.com> wrote:
You can use message_format facet directly [...] char const *gettext(char const *input) { try { std::locale l; boost::locale::message_facet<char> const&facet = std::use_facet<boost::locale::message_facet<char> >(l); char const *r = facet.get(my_domain_id,0,input); if(r) return r; return input; } [...] } Much better. But who exactly is in charge of the lifetime of the returned r pointer? And when does the memory get released exactly (if ever)? Just curious. The API doc you linked to doesn't say. Is there a higher-level doc that discussed memory management of those translated C strings? TIA, --DD
Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (3)
-
Artyom Beilis
-
Bastien Montagne
-
Dominique Devienne