2176. Special members for wstring_convert and wbuffer_convert

Section: D.18.1 [depr.conversions.string], D.18.2 [depr.conversions.buffer] Status: C++14 Submitter: Jonathan Wakely Opened: 2012-08-02 Last modified: 2017-09-10

Priority: Not Prioritized

View other active issues in [depr.conversions.string].

View all other issues in [depr.conversions.string].

View all issues with C++14 status.

Discussion:

See discussion following c++std-lib-32699.

The constructors for wstring_convert and wbuffer_convert should be explicit, to avoid implicit conversions which take ownership of a Codecvt pointer and delete it unexpectedly.

Secondly, [conversions.buffer] p11 describes a destructor which is not declared in the class synopsis in p2.

Finally, and most importantly, the definitions in [conversions.string] and [conversions.buffer] imply implicitly-defined copy constructors and assignment operators, which would do shallow copies of the owned Codecvt objects and result in undefined behaviour in the destructors.

Codecvt is not required to be CopyConstructible, so deep copies are not possible. The wstring_convert and wstring_buffer types could be made move-only, but the proposed resolution below doesn't do so because of the lack of preconditions regarding null Codecvt pointers and the absence of observer functions that would allow users to check preconditions (see also LWG 2175).

[2013-03-15 Issues Teleconference]

Moved to Review.

Jonathan pointed out that you can have an implicit constructor that takes ownership of a heap reference, which would result an unexpected deletion.

No-one really likes the 'naked new' in the interface here, either.

[2013-04-18, Bristol]

Proposed resolution:

This wording is relative to N3376.

  1. Edit the class template wstring_convert synopsis in [conversions.string] p2:

    explicit wstring_convert(Codecvt *pcvt = new Codecvt);
    wstring_convert(Codecvt *pcvt, state_type state);
    explicit wstring_convert(const byte_string& byte_err,
                             const wide_string& wide_err = wide_string());
    ~wstring_convert();
    
    wstring_convert(const wstring_convert&) = delete;
    wstring_convert& operator=(const wstring_convert&) = delete;
    				 
    
  2. Edit the signatures before [conversions.string] p16:

    explicit wstring_convert(Codecvt *pcvt = new Codecvt);
    wstring_convert(Codecvt *pcvt, state_type state);
    explicit wstring_convert(const byte_string& byte_err,
        const wide_string& wide_err = wide_string());
    
  3. Edit the class template wbuffer_convert synopsis in [conversions.buffer] p2:

    explicit wbuffer_convert(std::streambuf *bytebuf = 0,
                             Codecvt *pcvt = new Codecvt,
                             state_type state = state_type());
    
    ~wbuffer_convert();
    
    wbuffer_convert(const wbuffer_convert&) = delete;
    wbuffer_convert& operator=(const wbuffer_convert&) = delete;
    						 
    
  4. Edit the signature before [conversions.buffer] p10:

    explicit wbuffer_convert(std::streambuf *bytebuf = 0,
        Codecvt *pcvt = new Codecvt, state_type state = state_type());