[cfe-dev] [libc++] Should IO manipulators be noncopyable?
    Jim Porter 
    jvp4846 at g.rit.edu
       
    Tue Jul  8 15:44:04 PDT 2014
    
    
  
On 7/8/2014 1:46 PM, Marshall Clow wrote:
>
> On Jul 5, 2014, at 3:05 PM, Jim Porter <jvp4846 at g.rit.edu> wrote:
>
>> Recently, I was trying out the new std::quoted IO manipulator and came across an interesting issue: since libc++'s std::quoted is copyable (as are all the other IO manipulators I looked at), passing a temporary as the first argument introduces a lifetime bug in the following code:
>>
>>   auto ensure_printable(const std::wstring &s) {
>>     std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> conv;
>>     return std::quoted(conv.to_bytes(s));
>>   }
>>
>>   // ...
>>
>>   std::cout << ensure_printable(std::wstring(L"hi"));
>
> There’s an easy fix, btw - the object returned by quoted could capture the string by value, rather than reference.
> Make a copy.  :-(
That's true, but I'm not sure how useful that is. If we're copying the 
string, it's just about as bad, memory-wise, as stringifying the result 
of std::quoted and storing that:
   std::string ensure_printable(const std::wstring &s) {
     std::stringstream ss;
     std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> conv;
     ss << std::quoted(conv.to_bytes(s));
     return ss.str();
   }
This is obviously a bit uglier for people trying to indirectly use 
std::quoted like I was, but I think this is how it was intended to be 
used by the standard; making a copy of the result of std::quoted is 
technically undefined behavior, since the type is unspecified (and thus, 
it's unspecified if it's copyable).
Besides, making a copy of the string probably wouldn't help if the 
original code were slightly changed:
   auto ensure_printable(const std::wstring &s) {
     std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> conv;
     std::string converted = conv.to_bytes(s);
     return std::quoted(converted);
   }
That would pick up the third overload of std::quoted, which needs to 
hold a reference so that `stream >> std::quoted(blah)` works. Then we're 
back to the original problem.
> BTW - even simpler example
>
> auto boom ( const std::string &s ) { return std::quoted(s); }
> auto foo = boom ( “Hi Mom!” );
>
> foo now has a reference to a destructed string.
Good catch!
- Jim
    
    
More information about the cfe-dev
mailing list