I have encountered code which does this:
SomeObject parse (std::istream && input) {....
The input
argument is an rvalue reference, which normally means the function is intended to take ownership of the argument. That's not quite what is happening here.
The parse
function will completely consume the input stream, and it demands an rvalue reference because then calling code will give away ownership of the istream
and hence this is a signal that the input stream will be unusable.
I think this is okay because, since the parse
function doesn't actually move the object around, there is no danger of slicing out the subtype. This is basically behaving as a normal reference from parse
's point of view, only there is a kind of compilable comment to the calling function that you have to give up ownership of the stream.
Is this code actually safe? Or is there some overlooked subtlety which makes this dangerous?
SomeObject parse (std::istream && input)
is to get the function to only accept temporaries? – Harakiristd::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards. – Nybergstd::istream
interface. But the semantics here are IMHO questionable. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream afterparse()
returns!? In what way exactly doesparse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is "ownership" somehow "given back" to the calling code in this case? – Margaloparse(std::move(std::cin))
? – Inductiveprase(std::move(my_string_stream));
is much less shocking. – Gabistd::cin
and I should not use it afterwads. Got it. Neat". At least in my perception. Consider also the usage ofstd::stringstream
s andstd::fstream
s. – Nybergstd::cin
unusable? This aspect particularly doesn't make any sense to me given the very concept of a stream. A stream can be at EOF. That doesn't make that stream object unusable. A stream can be in a bad state. That doesn't make the object unusable… – Margaloparse
wants it to do. It's not promising that "I will destroy this stream so much you won't even be able to recongise what's left". It's expressing that "I want to own that stream, do whatever I want with it and you won't be using it for other things than assigning to it". – Nybergstd::istream
, the caller already has to assume that whoever gets the stream will read from it. If it reads beyond the end of the stream, the stream will be in an EOF state. If an error occurs, the stream will be in a bad state. In no case will the stream object itself be in an "unusable" state. That's what the whole concept of anstd::istream
is about… – Margaloparse(std::move(std::cin))
– Inductiveparse(std::move(std::cin))
a lie. Go ahead and parse everything fromstd::cin
. I could obviously do something with it afterwads (you can do pretty much everything inC++
), but I know I shouldn't. If you want to read fromstd::cin
in other way thanparse
does, then... don't useparse
? – Nybergparse
will read everything, doesn't mean that it becomes useless to the caller. It could, for example, do something asynchronously in another thread. For example, reads from the stream could block current thread, waiting for another thread to write to the same object. But if you force it to bestd::move
-d, you hint that it shouldn't be used that way. – Lesalesakparse
does something you don't want to do, then simply don't useparse
. – Nybergparse
doing anything that I don't want it to do, except for taking myistream
by r-value reference - and that is the OP's question - or at least close to it - "is it ok?", or as I interpret - "do I lose something by doing so?" – Lesalesakparse
could spawn a thread that will wait for any signal from given stream and in that case you would want to ensure that nobody else will ever use such stream. There are a few examples, but I think it's not the best place to discuss this idea. You certainly have valid points and I am leaning towards your position, but I still have some doubts. Let's wait for other possible answers. – Nybergparse
does, the premise of the question is that it renders the stream unreadable. If you can't agree that the premise might be true then replacestd::istream
withfoo
which can be anything compatible with the premise. – Gabi