Boost C++ Libraries: Ticket #3234: XML Serialization error when loading class that inherits from wstring https://svn.boost.org/trac10/ticket/3234 <p> Using version 1.37.0, but checked against SVN and it doesn't seem to have changed a lot. I'm sorry and I'll try the latest boost version, but please do not disregard this bug just because of the version. </p> <p> I've tested up until I reach basic_text_iprimitive::load(wstring &amp;t): </p> <pre class="wiki"> template&lt;class T&gt; void load(T &amp; t) { if(is.fail()) boost::serialization::throw_exception( archive_exception(archive_exception::stream_error) ); is &gt;&gt; t; } </pre><p> The value was "./" In this case t = "./&lt;/basePath&gt;" :-O </p> <p> (basePath thas the NVP name for the wstring value) </p> <p> As the end tag is taken as the actual value, trying to get the end tag will break the serialization when continuing the execution. </p> <p> Call stack: </p> <pre class="wiki"> CharacterEditor.exe!boost::archive::basic_text_iprimitive&lt;std::basic_istream&lt;wchar_t,std::char_traits&lt;wchar_t&gt; &gt; &gt;::load&lt;nt::wstring&gt;(nt::wstring &amp; t={...}) Line 87 C++ CharacterEditor.exe!boost::archive::xml_wiarchive_impl&lt;boost::archive::xml_wiarchive&gt;::load&lt;nt::wstring&gt;(nt::wstring &amp; t={...}) Line 63 C++ CharacterEditor.exe!boost::archive::load_access::load_primitive&lt;boost::archive::xml_wiarchive,nt::wstring&gt;(boost::archive::xml_wiarchive &amp; ar={...}, nt::wstring &amp; t={...}) Line 98 C++ CharacterEditor.exe!boost::archive::detail::load_non_pointer_type&lt;boost::archive::xml_wiarchive,nt::wstring&gt;::load_primitive::invoke(boost::archive::xml_wiarchive &amp; ar={...}, nt::wstring &amp; t={...}) Line 306 + 0xd bytes C++ CharacterEditor.exe!boost::archive::detail::load_non_pointer_type&lt;boost::archive::xml_wiarchive,nt::wstring&gt;::invoke(boost::archive::xml_wiarchive &amp; ar={...}, nt::wstring &amp; t={...}) Line 391 + 0xd bytes C++ CharacterEditor.exe!boost::archive::load&lt;boost::archive::xml_wiarchive,nt::wstring&gt;(boost::archive::xml_wiarchive &amp; ar={...}, nt::wstring &amp; t={...}) Line 514 + 0xd bytes C++ CharacterEditor.exe!boost::archive::detail::common_iarchive&lt;boost::archive::xml_wiarchive&gt;::load_override&lt;nt::wstring&gt;(nt::wstring &amp; t={...}, int __formal=0) Line 59 + 0x15 bytes C++ CharacterEditor.exe!boost::archive::basic_xml_iarchive&lt;boost::archive::xml_wiarchive&gt;::load_override&lt;nt::wstring&gt;(const boost::serialization::nvp&lt;nt::wstring&gt; &amp; t={...}, int __formal=0) Line 82 C++ &gt; CharacterEditor.exe!boost::archive::xml_wiarchive_impl&lt;boost::archive::xml_wiarchive&gt;::load_override&lt;boost::serialization::nvp&lt;nt::wstring&gt; const &gt;(const boost::serialization::nvp&lt;nt::wstring&gt; &amp; t={...}, int __formal=0) Line 79 C++ . . . . </pre><p> nt::string is almost the same as std::wstring </p> <pre class="wiki">namespace nt { class wstring : public std::wstring { /*some extra helper functions for initialization from a wxWidgets' wxString*/} } BOOST_CLASS_IMPLEMENTATION(nt::wstring, boost::serialization::primitive_type) namespace boost { namespace serialization { template&lt;class Archive&gt; void serialize(Archive &amp; ar, nt::wstring &amp;s, const unsigned int version) { ar &amp; static_cast&lt;std::wstring &amp;&gt;(s); } } } // namespace serialization // namespace boost </pre><p> The compiler is Microsoft Visual C++ Express 2008 (9) I did this hacks in order to get serialization templates to work under MSVC9: </p> <pre class="wiki">//HACK: enable serialization of MSVC9 hash_map #define BOOST_HAS_HASH #define BOOST_HASH_MAP_HEADER &lt;hash_map&gt; //HACK: disable resize of hash_map #define __MWERKS__ #include &lt;boost/serialization/hash_collections_load_imp.hpp&gt; #undef __MWERKS__ #include &lt;boost/serialization/hash_map.hpp&gt; </pre><p> Thanks for your time. -Martín </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3234 Trac 1.4.3 nitram.cero@… Tue, 30 Jun 2009 07:13:05 GMT <link>https://svn.boost.org/trac10/ticket/3234#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3234#comment:1</guid> <description> <p> The same happens with SVN version (checked) </p> <p> and also by doing this (that seems more proper): </p> <pre class="wiki">template&lt;class Archive&gt; void serialize(Archive &amp; ar, nt::wstring &amp;s, const unsigned int version) { ar &amp; boost::serialization::base_object&lt;std::wstring&gt;(s); } </pre><p> Regards -Martín </p> </description> <category>Ticket</category> </item> <item> <author>nitram.cero@…</author> <pubDate>Wed, 01 Jul 2009 16:04:42 GMT</pubDate> <title>version changed https://svn.boost.org/trac10/ticket/3234#comment:2 https://svn.boost.org/trac10/ticket/3234#comment:2 <ul> <li><strong>version</strong> <span class="trac-field-old">Boost 1.37.0</span> → <span class="trac-field-new">Boost Development Trunk</span> </li> </ul> <p> Ok, I've been investigating a bit more. </p> <p> Serialization in <strong>XML</strong> of nt::wstring (my std::wstring derived class) as a primitive makes it get loaded by a template instead of an specialized std::wstring function. And that reads until a space (sometimes including the end tag). </p> <p> If I don't define my nt::wstring class as a primitive type, and wrap the base (std::wstring) as a NVP, then I get a redundant tag (i.e: &lt;my_value&gt;&lt;base&gt;the string&lt;/base&gt;&lt;/my_value&gt;) </p> <p> Shouldn't be a wrapper to explicitly define that it's unnamed and shouldn't produce a tags? </p> <p> or maybe a having a "primitive_string_type" instead of "primitive_type" that has std::wstring and std::string specialized. </p> <pre class="wiki">BOOST_CLASS_IMPLEMENTATION(nt::wstring, boost::serialization::primitive_type) </pre><p> Fails, loads as with a generic template instead of std::wstring specific </p> <pre class="wiki">namespace boost { namespace serialization { template&lt;class Archive&gt; void serialize(Archive &amp; ar, nt::wstring &amp;s, const unsigned int version) { ar &amp; boost::serialization::make_nvp("base", static_cast&lt;std::wstring &amp;&gt;(s)); } } } // namespace serialization // namespace boost </pre><p> This works but for each string I have a redundant tag just for the base. </p> <p> For now I'll have it wrapped around "&lt;base&gt;" tags. I don't know if this trac entry should be of type Bugs or Feature request... I'll just leave it this way, feel free to change it. </p> <p> Regards -Martín </p> Ticket anonymous Wed, 01 Jul 2009 16:24:51 GMT keywords set https://svn.boost.org/trac10/ticket/3234#comment:3 https://svn.boost.org/trac10/ticket/3234#comment:3 <ul> <li><strong>keywords</strong> serialization wstring derived class added </li> </ul> Ticket Robert Ramey Thu, 09 Jul 2009 15:17:28 GMT <link>https://svn.boost.org/trac10/ticket/3234#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3234#comment:4</guid> <description> <p> usually this occurs when the saving archive is closed before the saving stream is flushed. Could you enclose a small example along with an xml archive which demonstrates this problem? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Thu, 09 Jul 2009 22:57:44 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3234#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3234#comment:5</guid> <description> <p> There is no problem saving, but loading. The output XML looks fine. </p> <p> But when loading a derived from std::wstring/string class, the loading <em>template specialization</em> is not contemplated, and the operator&gt;&gt; on the stream is called as if it were an int, float, any non-specialized type. </p> <p> I.e.: Instead of calling the loading function for the parameter wstring&amp;, it calls the generic one. </p> <p> There could be a class implementation that was primitive_string, besides primitive, to allow for customized std::string/wstring </p> <p> Regards -Martín </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Fri, 10 Jul 2009 19:45:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3234#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3234#comment:6</guid> <description> <p> How about attaching a small test program which shows the failure? </p> </description> <category>Ticket</category> </item> <item> <author>nitram.cero@…</author> <pubDate>Fri, 10 Jul 2009 23:39:43 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3234#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3234#comment:7</guid> <description> <p> No problem. (Using MSVC++ 2008 express) </p> <p> Important excerpts: </p> <pre class="wiki">namespace primitive { class wstring : public std::wstring { ... namespace object { class wstring : public std::wstring { ... BOOST_CLASS_IMPLEMENTATION(object::wstring, boost::serialization::object_serializable) BOOST_CLASS_IMPLEMENTATION(primitive::wstring, boost::serialization::primitive_type) ... template&lt;class Archive&gt; void serialize(Archive &amp; ar, object::wstring &amp;s, const unsigned int version) { ar &amp; boost::serialization::make_nvp("base", static_cast&lt;std::wstring &amp;&gt;(s)); //ar &amp; boost::serialization::base_object&lt;std::wstring&gt;(s); } </pre><p> Code: </p> <pre class="wiki"> #define _CRT_SECURE_NO_WARNINGS #include &lt;boost/archive/xml_woarchive.hpp&gt; #include &lt;boost/archive/xml_wiarchive.hpp&gt; #include &lt;boost/archive/xml_archive_exception.hpp&gt; #include &lt;boost/serialization/string.hpp&gt; #include &lt;string&gt; #include &lt;fstream&gt; #include &lt;iostream&gt; //Utility defines for better readability #define SERIALIZE_FUNCTION \ friend class boost::serialization::access; \ template&lt;class Archive&gt; \ void serialize(Archive &amp; serializable_archive, const unsigned int serializable_version) #define serializable_base(BASECLASS) boost::serialization::make_nvp(#BASECLASS, boost::serialization::base_object&lt; BASECLASS &gt;(*this)) #define serializable_variable(VAR) boost::serialization::make_nvp(#VAR, VAR) namespace primitive { class wstring : public std::wstring { public: wstring() { } wstring(const wchar_t *str) : std::wstring(str) { } wstring(const wstring &amp;wstr) : std::wstring(wstr) { } wstring(const std::wstring &amp;wstr) : std::wstring(wstr) { } wstring &amp;operator =(const wstring &amp;wstr) { operator =(static_cast&lt;const std::wstring &amp;&gt;(wstr)); return *this; } wstring &amp;operator =(const std::wstring &amp;wstr) { std::wstring::operator =(wstr); return *this; } wstring &amp;operator =(const wchar_t *str) { std::wstring::operator =(str); return *this; } //...custom stuff... }; } namespace object { class wstring : public std::wstring { public: wstring() { } wstring(const wchar_t *str) : std::wstring(str) { } wstring(const wstring &amp;wstr) : std::wstring(wstr) { } wstring(const std::wstring &amp;wstr) : std::wstring(wstr) { } wstring &amp;operator =(const wstring &amp;wstr) { operator =(static_cast&lt;const std::wstring &amp;&gt;(wstr)); return *this; } wstring &amp;operator =(const std::wstring &amp;wstr) { std::wstring::operator =(wstr); return *this; } wstring &amp;operator =(const wchar_t *str) { std::wstring::operator =(str); return *this; } //...custom stuff... }; } //BOOST_CLASS_IMPLEMENTATION(nt::wstring, boost::serialization::primitive_type) BOOST_CLASS_IMPLEMENTATION(object::wstring, boost::serialization::object_serializable) BOOST_CLASS_IMPLEMENTATION(primitive::wstring, boost::serialization::primitive_type) namespace boost { namespace serialization { template&lt;class Archive&gt; void serialize(Archive &amp; ar, object::wstring &amp;s, const unsigned int version) { ar &amp; boost::serialization::make_nvp("base", static_cast&lt;std::wstring &amp;&gt;(s)); //ar &amp; boost::serialization::base_object&lt;std::wstring&gt;(s); } } } // namespace serialization // namespace boost using std::wcout; using std::endl; template &lt;typename T&gt; void do_stuff(char *filename, const T &amp;value) { try { //save { T std_wstr = value; wcout &lt;&lt; "saving: " &lt;&lt; std_wstr &lt;&lt; endl; std::wofstream os(filename); boost::archive::xml_woarchive oxml(os); oxml &amp; serializable_variable(std_wstr); } //load { T std_wstr; std::wifstream os(filename); boost::archive::xml_wiarchive oxml(os); oxml &amp; serializable_variable(std_wstr); wcout &lt;&lt; "loaded: " &lt;&lt; std_wstr &lt;&lt; " " &lt;&lt; (std_wstr == value ? "(EQUAL)" : "(NOT EQUAL)") &lt;&lt; endl; } wcout &lt;&lt; "*** Success" &lt;&lt; endl; } catch(boost::archive::xml_archive_exception &amp;e) { wcout &lt;&lt; "*** Archive failure: " &lt;&lt; e.what() &lt;&lt; "***" &lt;&lt; endl; } catch(std::exception &amp;e) { wcout &lt;&lt; "*** Failure: " &lt;&lt; e.what() &lt;&lt; "***" &lt;&lt; endl; } } int main(int argc, char **argv) { wcout &lt;&lt; L"---------- std::wstring ----------" &lt;&lt; endl; //"official" wstring [OK] do_stuff&lt;std::wstring &gt;("_std1.xml", L"This is a test"); do_stuff&lt;std::wstring &gt;("_std2.xml", L"..."); wcout &lt;&lt; L"---------- object::wstring (SEE _object*.xml) ----------" &lt;&lt; endl; //derived as object [OK], BUT has TAGS surrounding the string in XML do_stuff&lt;object::wstring &gt;("_object1.xml", L"This is a test"); do_stuff&lt;object::wstring &gt;("_object2.xml", L"..."); wcout &lt;&lt; L"---------- primitive::wstring ----------" &lt;&lt; endl; //derived as primitive [FAILS] do_stuff&lt;primitive::wstring &gt;("_prim1.xml", L"This is a test"); do_stuff&lt;primitive::wstring &gt;("_prim2.xml", L"..."); return 0; } </pre><p> Output: </p> <pre class="wiki">---------- std::wstring ---------- saving: This is a test loaded: This is a test (EQUAL) *** Success saving: ... loaded: ... (EQUAL) *** Success ---------- object::wstring (SEE _object*.xml) ---------- saving: This is a test loaded: This is a test (EQUAL) *** Success saving: ... loaded: ... (EQUAL) *** Success ---------- primitive::wstring ---------- saving: This is a test *** Failure: stream error*** saving: ... loaded: ...&lt;/std_wstr&gt; (NOT EQUAL) *** Success </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Sun, 11 Oct 2009 22:37:54 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3234#comment:8 https://svn.boost.org/trac10/ticket/3234#comment:8 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">wontfix</span> </li> </ul> <p> OK - I looked into this. </p> <p> I'm not sure what you're trying to do, but here is what I've found. </p> <p> The "official" std::wstring works fine. It is marked as primitive and has special code inside of basic_text_iprimitive to handle it. </p> <p> Your "object:" version also works as expected. When using xml_archives tags are required for elements. There might be a way to suppress/override this but if there is I don't remember what it is. </p> <p> your "primitive:&#34; version fails with the string &#34;This is..". Since the type is marked primitive, when it comes time to load the string the following is called: </p> <p> is &gt;&gt; t where t is of type primitive::wstring </p> <p> since primitive::wstring is derived from std::string and t is passed by reference, t get's "promoted" to std::wstring for the is &gt;&gt; t operation. This operation is implemented by the standard library so that it stops when it gets a space. So you don't get the whole string back. Now things are out of whack when the end tag is searched for and the program bombs. </p> <p> Robert Ramey </p> Ticket