[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