Is it reasonable to take std::istream&& as a argument?
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?
c++ iostream rvalue-reference istream
|
show 17 more comments
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?
c++ iostream rvalue-reference istream
6
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
1
@SamVarshavchik or to force a programmer tostd::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.
– Fureeish
2 hours ago
1
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership ofstd::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.
– Fureeish
2 hours ago
1
So what can it possibly do to makestd::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…
– Michael Kenzel
2 hours ago
1
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago
|
show 17 more comments
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?
c++ iostream rvalue-reference istream
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?
c++ iostream rvalue-reference istream
c++ iostream rvalue-reference istream
asked 2 hours ago
spraffspraff
17.8k1485165
17.8k1485165
6
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
1
@SamVarshavchik or to force a programmer tostd::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.
– Fureeish
2 hours ago
1
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership ofstd::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.
– Fureeish
2 hours ago
1
So what can it possibly do to makestd::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…
– Michael Kenzel
2 hours ago
1
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago
|
show 17 more comments
6
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
1
@SamVarshavchik or to force a programmer tostd::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.
– Fureeish
2 hours ago
1
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership ofstd::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.
– Fureeish
2 hours ago
1
So what can it possibly do to makestd::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…
– Michael Kenzel
2 hours ago
1
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago
6
6
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
1
1
@SamVarshavchik or to force a programmer to
std::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.– Fureeish
2 hours ago
@SamVarshavchik or to force a programmer to
std::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.– Fureeish
2 hours ago
1
1
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership of
std::cin
and I should not use it afterwads. Got it. Neat". At least in my perception. Consider also the usage of std::stringstream
s and std::fstream
s.– Fureeish
2 hours ago
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership of
std::cin
and I should not use it afterwads. Got it. Neat". At least in my perception. Consider also the usage of std::stringstream
s and std::fstream
s.– Fureeish
2 hours ago
1
1
So what can it possibly do to make
std::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…– Michael Kenzel
2 hours ago
So what can it possibly do to make
std::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…– Michael Kenzel
2 hours ago
1
1
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago
|
show 17 more comments
4 Answers
4
active
oldest
votes
std::move
just produces an rvalue reference from an object and nothing more. The nature of an rvalue is such that you can assume nobody else will care about it's state after you're done with it. std::move
then is used to allow developpers to make that promise about objects with other value categories. In other words calling std::move
in a meaningful context is equivalent to saying "I promise I don't care about this object's state anymore".
Since you will be making the object essentially unusable and you want to make sure the caller won't use the object anymore using an rvalue reference enforces this expectation to some extent. It forces the caller to make that promise to your function. Failure to make the promise will result in a compiler error (assuming there isn't another valid overload). It does not matter if you actually move from the object or not, only that the original owner has agreed to forfeit it's ownership.
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
add a comment |
An std::istream
isn't moveable, so there's no practical benefit to this.
This already signals that the thing may be "modified", without the confusion of suggesting you're transferring ownership of the std::istream
object (which you're not doing, and can't do).
I can kind of see the rationale behind using this to say that the stream is being logically moved, but I think you have to make a distinction between "ownership of this thing is being transferred", and "I keep ownership of this thing but I will let you consume all of its services". Ownership transfer is quite well understood as a convention in C++, and this is not really it. What will a user of your code think when they have to write parse(std::move(std::cin))
?
Your way isn't "dangerous" though; you won't be able to do anything with that rvalue reference that you can't with an lvalue reference.
It would be far more self-documenting and conventional to just take an lvalue reference.
3
Takingrvalue
reference and moving is not necessarily married to each other.
– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of usingC++
syntax to express the intent. But that's just my opinion.
– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with astd::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.
– Lightness Races in Orbit
2 hours ago
|
show 4 more comments
What you're trying to do here is not "dangerous" in the sense that, given the current std::istream
interface, there don't seem to be any circumstances under wich taking an rvalue reference here would necessarily lead to undefined behavior when taking an lvalue reference wouldn't have. But the semantics of this whole contraption are IMHO very questionable at best. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream after parse()
returns!? In what way exactly does parse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is no one allowed to try read the rest? Is "ownership" somehow "given back" to the calling code in this case?
A stream is an abstract concept. The purpose of the stream abstraction is to serve as an interface through which someone can consume input without having to know where the data comes from, lives, or how it is accessed and managed. If the purpose of parse()
is to parse input from arbitrary sources, then it should not be concerned with the nature of the source. If it is concerned with the nature of the source, then it should request a specific kind of source. And this is where, IMHO, your interface contradicts itself. Currently, parse()
takes an arbitrary source. The interface says: I take whatever stream you give me, I don't care how it's implemented. As long as it's a stream, I can work with it. At the same time, it requires the caller to relinquish the object that actually implements the stream. The interface requires the caller to hand over something that the interface itself prevents any implementation behind the interface to ever know about, access, or use in any way. For example, how would I have parse()
read from an std::ifstream
? Who closes the file afterwards? If can't be the parser. It also can't be me because calling the parser forced me to hand over the object. At the same time, I know that the parser could never even know it had to close the file I handed over…
It'll still do the right thing in the end because there was no way an implementation of the interface could've actually done what the interface suggested it would do and so my std::ifstream
destructor will just run and close the file. But what exactly did we gain by lying to each other like that!? You promised to take over the object when you were never going to, I promised to never touch the object again when I knew I'll always have to…
add a comment |
Your assumption that rvalue reference parameter imply "taking ownership" is completely incorrect. Rvalue reference is just a specific kind of reference, which comes with its own initialization rules and overload resolution rules. No more, no less. Formally, it has no special affinity with "moving" or "taking ownership" of the referenced object.
It is true that support for move semantics is considered one of the primary purposes of rvalue references, but still you should not assume that this is their only purpose and that these features are somehow inseparable. Just like any other language feature, it might allow a significant number of well-developed alternative idiomatic uses.
An example quote similar to what you just quoted is actually present in the standard library itself. It is the extra overloads introduced in C++11 (and C++17, depending on some nuances)
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );
Their main purpose is to "bridge" the difference in the behavior between member and non-member overloads of operator <<
#include <string>
#include <sstream>
int main()
{
std::string s;
int a;
std::istringstream("123 456") >> a >> s;
std::istringstream("123 456") >> s >> a;
// Despite the obvious similarity, the first line is well-formed in C++03
// while the second isn't. Both lines are well-formed in C++11
}
It takes advantage of the fact that rvalue reference can bind to temporary objects and still see them as modifiable objects. In this case rvalue reference is used for purposes that have nothing to do with move semantics. This is perfectly normal.
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54220831%2fis-it-reasonable-to-take-stdistream-as-a-argument%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
std::move
just produces an rvalue reference from an object and nothing more. The nature of an rvalue is such that you can assume nobody else will care about it's state after you're done with it. std::move
then is used to allow developpers to make that promise about objects with other value categories. In other words calling std::move
in a meaningful context is equivalent to saying "I promise I don't care about this object's state anymore".
Since you will be making the object essentially unusable and you want to make sure the caller won't use the object anymore using an rvalue reference enforces this expectation to some extent. It forces the caller to make that promise to your function. Failure to make the promise will result in a compiler error (assuming there isn't another valid overload). It does not matter if you actually move from the object or not, only that the original owner has agreed to forfeit it's ownership.
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
add a comment |
std::move
just produces an rvalue reference from an object and nothing more. The nature of an rvalue is such that you can assume nobody else will care about it's state after you're done with it. std::move
then is used to allow developpers to make that promise about objects with other value categories. In other words calling std::move
in a meaningful context is equivalent to saying "I promise I don't care about this object's state anymore".
Since you will be making the object essentially unusable and you want to make sure the caller won't use the object anymore using an rvalue reference enforces this expectation to some extent. It forces the caller to make that promise to your function. Failure to make the promise will result in a compiler error (assuming there isn't another valid overload). It does not matter if you actually move from the object or not, only that the original owner has agreed to forfeit it's ownership.
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
add a comment |
std::move
just produces an rvalue reference from an object and nothing more. The nature of an rvalue is such that you can assume nobody else will care about it's state after you're done with it. std::move
then is used to allow developpers to make that promise about objects with other value categories. In other words calling std::move
in a meaningful context is equivalent to saying "I promise I don't care about this object's state anymore".
Since you will be making the object essentially unusable and you want to make sure the caller won't use the object anymore using an rvalue reference enforces this expectation to some extent. It forces the caller to make that promise to your function. Failure to make the promise will result in a compiler error (assuming there isn't another valid overload). It does not matter if you actually move from the object or not, only that the original owner has agreed to forfeit it's ownership.
std::move
just produces an rvalue reference from an object and nothing more. The nature of an rvalue is such that you can assume nobody else will care about it's state after you're done with it. std::move
then is used to allow developpers to make that promise about objects with other value categories. In other words calling std::move
in a meaningful context is equivalent to saying "I promise I don't care about this object's state anymore".
Since you will be making the object essentially unusable and you want to make sure the caller won't use the object anymore using an rvalue reference enforces this expectation to some extent. It forces the caller to make that promise to your function. Failure to make the promise will result in a compiler error (assuming there isn't another valid overload). It does not matter if you actually move from the object or not, only that the original owner has agreed to forfeit it's ownership.
answered 2 hours ago
François AndrieuxFrançois Andrieux
15.7k32647
15.7k32647
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
add a comment |
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
Mostly agreed but I still don't see why you'd want to do that to a stream. It's unnecessarily constrictive unless there are domain constraints the OP hasn't mentioned. Michael's answer puts it quite nicely.
– Lightness Races in Orbit
45 mins ago
add a comment |
An std::istream
isn't moveable, so there's no practical benefit to this.
This already signals that the thing may be "modified", without the confusion of suggesting you're transferring ownership of the std::istream
object (which you're not doing, and can't do).
I can kind of see the rationale behind using this to say that the stream is being logically moved, but I think you have to make a distinction between "ownership of this thing is being transferred", and "I keep ownership of this thing but I will let you consume all of its services". Ownership transfer is quite well understood as a convention in C++, and this is not really it. What will a user of your code think when they have to write parse(std::move(std::cin))
?
Your way isn't "dangerous" though; you won't be able to do anything with that rvalue reference that you can't with an lvalue reference.
It would be far more self-documenting and conventional to just take an lvalue reference.
3
Takingrvalue
reference and moving is not necessarily married to each other.
– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of usingC++
syntax to express the intent. But that's just my opinion.
– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with astd::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.
– Lightness Races in Orbit
2 hours ago
|
show 4 more comments
An std::istream
isn't moveable, so there's no practical benefit to this.
This already signals that the thing may be "modified", without the confusion of suggesting you're transferring ownership of the std::istream
object (which you're not doing, and can't do).
I can kind of see the rationale behind using this to say that the stream is being logically moved, but I think you have to make a distinction between "ownership of this thing is being transferred", and "I keep ownership of this thing but I will let you consume all of its services". Ownership transfer is quite well understood as a convention in C++, and this is not really it. What will a user of your code think when they have to write parse(std::move(std::cin))
?
Your way isn't "dangerous" though; you won't be able to do anything with that rvalue reference that you can't with an lvalue reference.
It would be far more self-documenting and conventional to just take an lvalue reference.
3
Takingrvalue
reference and moving is not necessarily married to each other.
– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of usingC++
syntax to express the intent. But that's just my opinion.
– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with astd::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.
– Lightness Races in Orbit
2 hours ago
|
show 4 more comments
An std::istream
isn't moveable, so there's no practical benefit to this.
This already signals that the thing may be "modified", without the confusion of suggesting you're transferring ownership of the std::istream
object (which you're not doing, and can't do).
I can kind of see the rationale behind using this to say that the stream is being logically moved, but I think you have to make a distinction between "ownership of this thing is being transferred", and "I keep ownership of this thing but I will let you consume all of its services". Ownership transfer is quite well understood as a convention in C++, and this is not really it. What will a user of your code think when they have to write parse(std::move(std::cin))
?
Your way isn't "dangerous" though; you won't be able to do anything with that rvalue reference that you can't with an lvalue reference.
It would be far more self-documenting and conventional to just take an lvalue reference.
An std::istream
isn't moveable, so there's no practical benefit to this.
This already signals that the thing may be "modified", without the confusion of suggesting you're transferring ownership of the std::istream
object (which you're not doing, and can't do).
I can kind of see the rationale behind using this to say that the stream is being logically moved, but I think you have to make a distinction between "ownership of this thing is being transferred", and "I keep ownership of this thing but I will let you consume all of its services". Ownership transfer is quite well understood as a convention in C++, and this is not really it. What will a user of your code think when they have to write parse(std::move(std::cin))
?
Your way isn't "dangerous" though; you won't be able to do anything with that rvalue reference that you can't with an lvalue reference.
It would be far more self-documenting and conventional to just take an lvalue reference.
edited 2 hours ago
answered 2 hours ago
Lightness Races in OrbitLightness Races in Orbit
286k51466788
286k51466788
3
Takingrvalue
reference and moving is not necessarily married to each other.
– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of usingC++
syntax to express the intent. But that's just my opinion.
– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with astd::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.
– Lightness Races in Orbit
2 hours ago
|
show 4 more comments
3
Takingrvalue
reference and moving is not necessarily married to each other.
– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of usingC++
syntax to express the intent. But that's just my opinion.
– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with astd::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.
– Lightness Races in Orbit
2 hours ago
3
3
Taking
rvalue
reference and moving is not necessarily married to each other.– SergeyA
2 hours ago
Taking
rvalue
reference and moving is not necessarily married to each other.– SergeyA
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
@SergeyA Not seeing the purpose of an rvalue reference if you're not going to transfer ownership via a move (and you don't want to limit calls to rvalue expressions for arcane overloading reasons). Can you give an example of when this would be useful?
– Lightness Races in Orbit
2 hours ago
2
2
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of using
C++
syntax to express the intent. But that's just my opinion.– Fureeish
2 hours ago
"Can you give an example", well, the code in the question... At least in my opinion, the fact that one will transfer ownership of the input stream (which passing by rvalue reference means) will indicate that noone should try to extract from it afterwards, which I consider a neat way of using
C++
syntax to express the intent. But that's just my opinion.– Fureeish
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
You gave one yourself - you want your call be limited to rvalues. For example, (I am not saying this OPs case, I think the question isn't clear and closable) one might want to request that object provided to the function is a "scratchpad". I am using it myself in a certain case.
– SergeyA
2 hours ago
1
1
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with a
std::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.– Lightness Races in Orbit
2 hours ago
Transferring ownership is quite a well-defined context in C++ and it usually involves a move. You simply cannot do that with a
std::istream
. You can make your function accept only an rvalue to signify that it's going to read all the data from the stream, sure, but that's not what transferring ownership has ever meant in C++, so this would be quite strange IMO! I mean I can kind of see it, but I can't see that it's worthwhile.– Lightness Races in Orbit
2 hours ago
|
show 4 more comments
What you're trying to do here is not "dangerous" in the sense that, given the current std::istream
interface, there don't seem to be any circumstances under wich taking an rvalue reference here would necessarily lead to undefined behavior when taking an lvalue reference wouldn't have. But the semantics of this whole contraption are IMHO very questionable at best. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream after parse()
returns!? In what way exactly does parse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is no one allowed to try read the rest? Is "ownership" somehow "given back" to the calling code in this case?
A stream is an abstract concept. The purpose of the stream abstraction is to serve as an interface through which someone can consume input without having to know where the data comes from, lives, or how it is accessed and managed. If the purpose of parse()
is to parse input from arbitrary sources, then it should not be concerned with the nature of the source. If it is concerned with the nature of the source, then it should request a specific kind of source. And this is where, IMHO, your interface contradicts itself. Currently, parse()
takes an arbitrary source. The interface says: I take whatever stream you give me, I don't care how it's implemented. As long as it's a stream, I can work with it. At the same time, it requires the caller to relinquish the object that actually implements the stream. The interface requires the caller to hand over something that the interface itself prevents any implementation behind the interface to ever know about, access, or use in any way. For example, how would I have parse()
read from an std::ifstream
? Who closes the file afterwards? If can't be the parser. It also can't be me because calling the parser forced me to hand over the object. At the same time, I know that the parser could never even know it had to close the file I handed over…
It'll still do the right thing in the end because there was no way an implementation of the interface could've actually done what the interface suggested it would do and so my std::ifstream
destructor will just run and close the file. But what exactly did we gain by lying to each other like that!? You promised to take over the object when you were never going to, I promised to never touch the object again when I knew I'll always have to…
add a comment |
What you're trying to do here is not "dangerous" in the sense that, given the current std::istream
interface, there don't seem to be any circumstances under wich taking an rvalue reference here would necessarily lead to undefined behavior when taking an lvalue reference wouldn't have. But the semantics of this whole contraption are IMHO very questionable at best. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream after parse()
returns!? In what way exactly does parse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is no one allowed to try read the rest? Is "ownership" somehow "given back" to the calling code in this case?
A stream is an abstract concept. The purpose of the stream abstraction is to serve as an interface through which someone can consume input without having to know where the data comes from, lives, or how it is accessed and managed. If the purpose of parse()
is to parse input from arbitrary sources, then it should not be concerned with the nature of the source. If it is concerned with the nature of the source, then it should request a specific kind of source. And this is where, IMHO, your interface contradicts itself. Currently, parse()
takes an arbitrary source. The interface says: I take whatever stream you give me, I don't care how it's implemented. As long as it's a stream, I can work with it. At the same time, it requires the caller to relinquish the object that actually implements the stream. The interface requires the caller to hand over something that the interface itself prevents any implementation behind the interface to ever know about, access, or use in any way. For example, how would I have parse()
read from an std::ifstream
? Who closes the file afterwards? If can't be the parser. It also can't be me because calling the parser forced me to hand over the object. At the same time, I know that the parser could never even know it had to close the file I handed over…
It'll still do the right thing in the end because there was no way an implementation of the interface could've actually done what the interface suggested it would do and so my std::ifstream
destructor will just run and close the file. But what exactly did we gain by lying to each other like that!? You promised to take over the object when you were never going to, I promised to never touch the object again when I knew I'll always have to…
add a comment |
What you're trying to do here is not "dangerous" in the sense that, given the current std::istream
interface, there don't seem to be any circumstances under wich taking an rvalue reference here would necessarily lead to undefined behavior when taking an lvalue reference wouldn't have. But the semantics of this whole contraption are IMHO very questionable at best. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream after parse()
returns!? In what way exactly does parse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is no one allowed to try read the rest? Is "ownership" somehow "given back" to the calling code in this case?
A stream is an abstract concept. The purpose of the stream abstraction is to serve as an interface through which someone can consume input without having to know where the data comes from, lives, or how it is accessed and managed. If the purpose of parse()
is to parse input from arbitrary sources, then it should not be concerned with the nature of the source. If it is concerned with the nature of the source, then it should request a specific kind of source. And this is where, IMHO, your interface contradicts itself. Currently, parse()
takes an arbitrary source. The interface says: I take whatever stream you give me, I don't care how it's implemented. As long as it's a stream, I can work with it. At the same time, it requires the caller to relinquish the object that actually implements the stream. The interface requires the caller to hand over something that the interface itself prevents any implementation behind the interface to ever know about, access, or use in any way. For example, how would I have parse()
read from an std::ifstream
? Who closes the file afterwards? If can't be the parser. It also can't be me because calling the parser forced me to hand over the object. At the same time, I know that the parser could never even know it had to close the file I handed over…
It'll still do the right thing in the end because there was no way an implementation of the interface could've actually done what the interface suggested it would do and so my std::ifstream
destructor will just run and close the file. But what exactly did we gain by lying to each other like that!? You promised to take over the object when you were never going to, I promised to never touch the object again when I knew I'll always have to…
What you're trying to do here is not "dangerous" in the sense that, given the current std::istream
interface, there don't seem to be any circumstances under wich taking an rvalue reference here would necessarily lead to undefined behavior when taking an lvalue reference wouldn't have. But the semantics of this whole contraption are IMHO very questionable at best. What does it mean for the calling code to "give away ownership" but at the same time "not transferring it"? Who "owns" the stream after parse()
returns!? In what way exactly does parse()
make the stream "unusable"? What if parsing fails due to some error before the entire stream is "consumed"? Is the stream "unusable" then!? Is no one allowed to try read the rest? Is "ownership" somehow "given back" to the calling code in this case?
A stream is an abstract concept. The purpose of the stream abstraction is to serve as an interface through which someone can consume input without having to know where the data comes from, lives, or how it is accessed and managed. If the purpose of parse()
is to parse input from arbitrary sources, then it should not be concerned with the nature of the source. If it is concerned with the nature of the source, then it should request a specific kind of source. And this is where, IMHO, your interface contradicts itself. Currently, parse()
takes an arbitrary source. The interface says: I take whatever stream you give me, I don't care how it's implemented. As long as it's a stream, I can work with it. At the same time, it requires the caller to relinquish the object that actually implements the stream. The interface requires the caller to hand over something that the interface itself prevents any implementation behind the interface to ever know about, access, or use in any way. For example, how would I have parse()
read from an std::ifstream
? Who closes the file afterwards? If can't be the parser. It also can't be me because calling the parser forced me to hand over the object. At the same time, I know that the parser could never even know it had to close the file I handed over…
It'll still do the right thing in the end because there was no way an implementation of the interface could've actually done what the interface suggested it would do and so my std::ifstream
destructor will just run and close the file. But what exactly did we gain by lying to each other like that!? You promised to take over the object when you were never going to, I promised to never touch the object again when I knew I'll always have to…
edited 40 mins ago
answered 1 hour ago
Michael KenzelMichael Kenzel
4,073719
4,073719
add a comment |
add a comment |
Your assumption that rvalue reference parameter imply "taking ownership" is completely incorrect. Rvalue reference is just a specific kind of reference, which comes with its own initialization rules and overload resolution rules. No more, no less. Formally, it has no special affinity with "moving" or "taking ownership" of the referenced object.
It is true that support for move semantics is considered one of the primary purposes of rvalue references, but still you should not assume that this is their only purpose and that these features are somehow inseparable. Just like any other language feature, it might allow a significant number of well-developed alternative idiomatic uses.
An example quote similar to what you just quoted is actually present in the standard library itself. It is the extra overloads introduced in C++11 (and C++17, depending on some nuances)
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );
Their main purpose is to "bridge" the difference in the behavior between member and non-member overloads of operator <<
#include <string>
#include <sstream>
int main()
{
std::string s;
int a;
std::istringstream("123 456") >> a >> s;
std::istringstream("123 456") >> s >> a;
// Despite the obvious similarity, the first line is well-formed in C++03
// while the second isn't. Both lines are well-formed in C++11
}
It takes advantage of the fact that rvalue reference can bind to temporary objects and still see them as modifiable objects. In this case rvalue reference is used for purposes that have nothing to do with move semantics. This is perfectly normal.
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
add a comment |
Your assumption that rvalue reference parameter imply "taking ownership" is completely incorrect. Rvalue reference is just a specific kind of reference, which comes with its own initialization rules and overload resolution rules. No more, no less. Formally, it has no special affinity with "moving" or "taking ownership" of the referenced object.
It is true that support for move semantics is considered one of the primary purposes of rvalue references, but still you should not assume that this is their only purpose and that these features are somehow inseparable. Just like any other language feature, it might allow a significant number of well-developed alternative idiomatic uses.
An example quote similar to what you just quoted is actually present in the standard library itself. It is the extra overloads introduced in C++11 (and C++17, depending on some nuances)
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );
Their main purpose is to "bridge" the difference in the behavior between member and non-member overloads of operator <<
#include <string>
#include <sstream>
int main()
{
std::string s;
int a;
std::istringstream("123 456") >> a >> s;
std::istringstream("123 456") >> s >> a;
// Despite the obvious similarity, the first line is well-formed in C++03
// while the second isn't. Both lines are well-formed in C++11
}
It takes advantage of the fact that rvalue reference can bind to temporary objects and still see them as modifiable objects. In this case rvalue reference is used for purposes that have nothing to do with move semantics. This is perfectly normal.
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
add a comment |
Your assumption that rvalue reference parameter imply "taking ownership" is completely incorrect. Rvalue reference is just a specific kind of reference, which comes with its own initialization rules and overload resolution rules. No more, no less. Formally, it has no special affinity with "moving" or "taking ownership" of the referenced object.
It is true that support for move semantics is considered one of the primary purposes of rvalue references, but still you should not assume that this is their only purpose and that these features are somehow inseparable. Just like any other language feature, it might allow a significant number of well-developed alternative idiomatic uses.
An example quote similar to what you just quoted is actually present in the standard library itself. It is the extra overloads introduced in C++11 (and C++17, depending on some nuances)
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );
Their main purpose is to "bridge" the difference in the behavior between member and non-member overloads of operator <<
#include <string>
#include <sstream>
int main()
{
std::string s;
int a;
std::istringstream("123 456") >> a >> s;
std::istringstream("123 456") >> s >> a;
// Despite the obvious similarity, the first line is well-formed in C++03
// while the second isn't. Both lines are well-formed in C++11
}
It takes advantage of the fact that rvalue reference can bind to temporary objects and still see them as modifiable objects. In this case rvalue reference is used for purposes that have nothing to do with move semantics. This is perfectly normal.
Your assumption that rvalue reference parameter imply "taking ownership" is completely incorrect. Rvalue reference is just a specific kind of reference, which comes with its own initialization rules and overload resolution rules. No more, no less. Formally, it has no special affinity with "moving" or "taking ownership" of the referenced object.
It is true that support for move semantics is considered one of the primary purposes of rvalue references, but still you should not assume that this is their only purpose and that these features are somehow inseparable. Just like any other language feature, it might allow a significant number of well-developed alternative idiomatic uses.
An example quote similar to what you just quoted is actually present in the standard library itself. It is the extra overloads introduced in C++11 (and C++17, depending on some nuances)
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );
Their main purpose is to "bridge" the difference in the behavior between member and non-member overloads of operator <<
#include <string>
#include <sstream>
int main()
{
std::string s;
int a;
std::istringstream("123 456") >> a >> s;
std::istringstream("123 456") >> s >> a;
// Despite the obvious similarity, the first line is well-formed in C++03
// while the second isn't. Both lines are well-formed in C++11
}
It takes advantage of the fact that rvalue reference can bind to temporary objects and still see them as modifiable objects. In this case rvalue reference is used for purposes that have nothing to do with move semantics. This is perfectly normal.
edited 39 mins ago
answered 53 mins ago
AnTAnT
258k32414656
258k32414656
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
add a comment |
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
What are those purposes? I think that's the key point to this question. If you can explain what purpose this holds in that example, and how it relates to the OP's situation, that's probably the answer.
– Lightness Races in Orbit
47 mins ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54220831%2fis-it-reasonable-to-take-stdistream-as-a-argument%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e) {
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom)) {
StackExchange.using('gps', function() { StackExchange.gps.track('embedded_signup_form.view', { location: 'question_page' }); });
$window.unbind('scroll', onScroll);
}
};
$window.on('scroll', onScroll);
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
6
Undoubtedly the C++ language lawyers will have a few things to say about this. In the meantime, can you define the terms "okay," "safe," "reasonable" and "dangerous" within the context of your question, please? One man's cognac is another man's poison.
– Robert Harvey♦
2 hours ago
1
@SamVarshavchik or to force a programmer to
std::move
the input stream that's worked on, which will indicate that noone should try to extract from it afterwards.– Fureeish
2 hours ago
1
@Caleth and after the initial "WTF" you begin to understand that "oh, so it will parse the entire input, since I am giving up the ownership of
std::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.– Fureeish
2 hours ago
1
So what can it possibly do to make
std::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…– Michael Kenzel
2 hours ago
1
But what's the point of introducing this arbitrary restriction to the interface when there's literally nothing an implementation could possibly do to "take advantage" of it!?
– Michael Kenzel
2 hours ago