[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