8

The C++11's std::wstring_convert works great* for the standard UTF-8 <-> UTF-16/UCS2/UCS4 conversions. However, when I attempted to instantiate a wstring_convert or wbuffer_convert with a facet not from <codecvt>, it didn't work as expected:

// works as expected
std::wstring_convert<std::codecvt_utf8<wchar_t>> ucs4conv;

// Now, by analogy, I want to try this:
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> gbconv(
        new std::codecvt_byname<wchar_t, char, std::mbstate_t>("zh_CN.gb18030"));

Clang++ errors out saying "calling a protected destructor of codecvt<> in ~wstring_convert"

Visual Studio allows it (although it lacks that locale, but that's another story), because its wstring_convert pawns the lifetime management of the facet pointer off to a locale object it holds as a member, and locales know how to delete pointers to all facets.

Is Visual Studio right and libc++ wrong?

* as implemented in clang++-2.9/libc++-svn and Visual Studio 2010 EE SP1, the following example works on both, but not in GCC, sadly: https://ideone.com/hywz6

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Cubbi
  • 46,567
  • 13
  • 103
  • 169

1 Answers1

10

I am admittedly biased in this answer. But I will attempt to back up my claims with references to N3290 (which is unfortunately no longer publicly available). And I will also offer a solution.

Analysis:

The synopsis of wstring_convert in [conversions.string]/p2 includes:

private:
  byte_string byte_err_string;  // exposition only
  wide_string wide_err_string;  // exposition only
  Codecvt *cvtptr;              // exposition only
  state_type cvtstate;          // exposition only
  size_t cvtcount;              // exposition only

The "exposition only" means that the wstring_convert doesn't have to have these members in this order by this spelling. But "exposition only" members are used to describe the effects of various members, and those specifications are binding.

And so the question appears to become:

What is the specification of ~wstring_convert()?

This is found in p17 of the same section ([conversions.string]):

~wstring_convert();

Effects: The destructor shall delete cvtptr.

That implies to me that ~Codecvt() must be accessible, and therefore libc++ is following the C++11 specification.

I would also agree that this is a royal pain in the butt.

Solution:

Having all of the C++98/03 facets have protected destructors has turned out to be very inconvenient. Here's an adaptor that can take any facet and give it a public destructor:

template <class Facet>
class usable_facet
    : public Facet
{
public:
    template <class ...Args>
        usable_facet(Args&& ...args)
            : Facet(std::forward<Args>(args)...) {}
    ~usable_facet() {}
};

You can now use this general purpose adaptor in your code:

typedef usable_facet<std::codecvt<wchar_t, char, std::mbstate_t>> C;
std::wstring_convert<C> gbconv(new C("zh_CN.gb18030"));

Hope this helps.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • It also says that the template argument Codecvt `meets the requirements of the standard code-conversion facet std::codecvt<` (§ 22.3.3.2.2/3). And the std::codecvt is defined with a protected dtor. Perhaps "shall delete `cvtptr`" does not mean "same as `delete cvtptr;`"? Thanks for the wrapper though. – Cubbi Sep 29 '11 at 16:11
  • I'll open an inquiry. At this point I'm unsure of what the best resolution would be. It seems a shame to me to go to the expense of creating a new `locale` to hold `Codecvt*` where otherwise a simple pointer store would do. – Howard Hinnant Sep 29 '11 at 16:18
  • 1
    Oh, just looked it up. The issue has already been opened and decided NAD: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#721 – Howard Hinnant Sep 29 '11 at 16:24
  • 1
    @Howard : Marking the issue as NAD because "*codecvt isn't intended for beginning programmers*" seems like a bit of a cop out. Is there any possibility of reopening the issue? – ildjarn Sep 29 '11 at 16:43
  • Anyone can open an issue. If you go this route you should point directly to the issue you want reopened, else your complaint will be immediately marked as a duplicate. Here are the instructions for opening an issue: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#submit_issue – Howard Hinnant Sep 29 '11 at 17:04
  • @ildjarn - From what I remember, the reason for the NAD was that the designers of wstring_convert were well aware of the problem all along. Thus technically not a defect, but works-as-designed. – Bo Persson Sep 29 '11 at 17:46
  • 1
    @Bo : Except that in this case, 'works-as-designed' apparently means 'doesn't work without extra, pointless effort'. :-/ (Also, I did note that you submitted the original issue, so I figured you had more insight to offer. :-]) – ildjarn Sep 29 '11 at 18:08