Online references have rather brief and vague descriptions on the purpose of std::iostream::sentry. When should I concern myself with this little critter? If it's only intended to be used internally, why make it public?
It's used whenever you need to extract or output data with a stream. That is, whenever you make an operator>>, the extraction operator, or operator<<, the insertion operator.
It's purpose is to simplify the logic: "Are any fail bits set? Synchronize the buffers. For input streams, optionally get any whitespace out of the way. Okay, ready?"
All extraction stream operators should begin with:
// second parameter to true to not skip whitespace, for input that uses it
const std::istream::sentry ok(stream, icareaboutwhitespace);
if (ok)
{
// ...
}
And all insertion stream operators should begin with:
const std::ostream::sentry ok(stream);
if (ok)
{
// ...
}
It's just a cleaner way of doing (something similar to):
if (stream.good())
{
if (stream.tie())
stream.tie()->sync();
// the second parameter
if (!noskipwhitespace && stream.flags() & ios_base::skipws)
{
stream >> std::ws;
}
}
if (stream.good())
{
// ...
}
ostream just skips the whitespace part.
Most people will never write any code that needs to deal with creating sentry objects. A sentry object is needed when/if you extract data from (or insert it into) the stream buffer that underlies the stream object itself.
As long as your insertion/extraction operator uses other iostream members/operators to do its work, it does not have to deal with creating a sentry object (because those other iostream operators will create and destroy sentry objects as needed).
Formatted input for anything but the basic types (int, double, etc.) doesn't make a lot of sense, and arguably only from them when taken from a non-interactive stream such as an istringstream. So you should probably not be implementing op>> in the first place, and thus not have to worry about sentry objects.
Related
I don't understand the design decisions behind the C++ getline function.
Why does it take a stream and a string by reference as arguments, only to return the same stream that was passed in? It seems more intuitive to only take the stream as an argument, then return the string that was read. Returning the same stream lets you chain the call, but would anyone really want to use getline(getline(stream, x), y)?
Additionally, why is the function not in the std namespace like the rest of the standard library?
If the function returned a string, there would be no way of indicating that the read failed, as all string values are valid values that could be returned by this (or any other) function. On the other hand, a stream has lots of error indicator flags that can be tested by the code that calls getline. So people can write code like:
while( std::getline( std::cin, somestring )) {
// do stuff with somestring
}
and it is hard to see how you could write similar code if getline returned a string.
why is the function not in the std namespace like the rest of the standard library?
It is in the std namespace - what makes you think otherwise?
Why does it take a stream and a string by reference as arguments, only to return the same stream that was passed in?
It is a common pattern in the stream library to do that. It means you can test the operation being performed as you perform it. For example:
std::string line;
while(std::getline(std::cin, line))
{
// use line here because we know the read succeeded
}
You can also make succinct parsers by "chaining" stream functions:
std::string key, value;
if(std::getline(std::getline(in, key, '='), value))
my_map[key] = value;
It seems more intuitive to only take the stream as an argument, then return the string that was read.
The problem with returning a new string every call is that you are constantly allocating new memory for them instead of reusing the memory already allocated to the string you passed in or that it gained while iterating through a loop.
// Here line will not need to allocate memory every time
// through the loop. Only when it finds a longer line than
// it has capacity for:
std::string line;
while(std::getline(std::cin, line))
{
// use line here because we know the read succeeded
}
I am trying to write my program so that it can process either StdIn or a file specified on the command line.
I'm doing this by trying to initialize a reference to an istream to either refer to cin or an ifstream, using a conditional.
(similar techniques are described here and here)
But when I try with ifstream, I seem to get an error that the basic_istream move-constructor is declared protected.
istream& refToCIN ( cin ); // This is OK
const istream& refToFile = ifstream(args[1]); // This is OK
const istream& inStream ( FileIsProvided()? ifstream(args[1]) : cin );
// This causes error:
// std::basic_istream<char,std::char_traits<char>>::basic_istream' :
// cannot access protected member declared in class std::basic_istream<char,std::char_traits<char>>
ProcessStream(inStream); // This could either be a file or cin
Can this be reasonably done this way? Is there a good alternative I'm overlooking?
The problem with your code is following:
Your left-hand side of the ternary operator is a temporary (rvalue). However, your right hand-side is an lvalue (cin is an lvalue). As a result, compiler is trying to create a temporary out of cin, and fails because of copy constructor being not available.
As for the sultions - you can simply replace rdbuf() of cin with rdbuf() of your file, and use cin everywhere.
Here's the ultimate solution OP came up with:
ifstream file;
std::streambuf* old_cin_buf = cin.rdbuf(); // Store the old value
if (FileIsProvided())
{
file.open(args[1]);
old_cin_buf = cin.rdbuf(file.rdbuf()); // Replace the ReadBuffer on cin.
// Store the previous value as well.
}
// Use cin for all operations now. It will either use the File or StdIn as appropriate.
...
// Restore the original value, in case it was changed by using a file.
cin.rdbuf(old_cin_buf); // This is better be done before file object here goes out of scope
This smells like an XY problem because you don't need a ternary conditional or reference here.
As a matter of convention, many programs use - to denote stdin rather than omitting a filename. That's one possible avenue. On a similar line of thought, I would use Boost.ProgramOptions or getopt instead of manually parsing the command line. This will indirectly solve your XY problem as it'll make the FileIsProvided() function redundant and you'll be getting your options via other methods than using argv[1] directly.
If you have C++11, there's smart pointers or std::reference_wrapper, which allows you to "reseat" references.
As a anti-motivator, consider that classes like ostream_joiner keep a pointer to their internal stream objects, not a reference. Besides, I doubt that you enjoy the thought of having to deal with dangling references from innocuous looking code.
Otherwise...
if (FileIsProvided())
{
std::ifstream ifs(argv[1]);
if (ifs)
{
ProcessStream(ifs);
}
} else {
ProcessStream(std::cin);
}
Is there a (clean) way to manipulate some text from std::cin before inserting it into a std::string, so that the following would work:
cin >> setw(80) >> Uppercase >> mystring;
where mystring is std::string (I don't want to use any wrappers for strings).
Uppercase is a manipulator. I think it needs to act on the Chars in the buffer directly (no matter what is considered uppercase rather than lowercase now). Such a manipulator seems difficult to implement in a clean way, as user-defined manipulators, as far as I know, are used to just change or mix some pre-determined format flags easily.
(Non-extended) manipulators usually only set flags and data which the extractors afterwards read and react to. (That is what xalloc, iword, and pword are for.) What you could, obviously, do, is to write something analogous to std::get_money:
struct uppercasify {
uppercasify(std::string &s) : ref(s) {}
uppercasify(const uppercasify &other) : ref(other.ref) {}
std::string &ref;
}
std::istream &operator>>(std::istream &is, uppercasify uc) { // or &&uc in C++11
is >> uc.ref;
boost::to_upper(uc.ref);
return is;
}
cin >> setw(80) >> uppercasify(mystring);
Alternatively, cin >> uppercase could return not a reference to cin, but an instantiation of some (template) wrapper class uppercase_istream, with the corresponding overload for operator>>. I don't think having a manipulator modify the underlying stream buffer's contents is a good idea.
If you're desperate enough, I guess you could also imbue a hand-crafted locale resulting in uppercasing strings. I don't think I'd let anything like that go through a code review, though – it's simply just waiting to surprise and bite the next person working on the code.
You may want to check out boost iostreams. Its framework allows defining filters which can manipulate the stream. http://www.boost.org/doc/libs/1_49_0/libs/iostreams/doc/index.html
I would like to test if a std::istream has reached the end without reading from it.
I know that I can check for EOF like this:
if (is >> something)
but this has a series of problems. Imagine there are many, possibly virtual, methods/functions which expect std::istream& passed as an argument.
This would mean I have to do the "housework" of checking for EOF in each of them, possibly with different type of something variable, or create some weird wrapper which would handle the scenario of calling the input methods.
All I need to do is:
if (!IsEof(is)) Input(is);
the method IsEof should guarantee that the stream is not changed for reading, so that the above line is equivalent to:
Input(is)
as regards the data read in the Input method.
If there is no generic solution which would word for and std::istream, is there any way to do this for std::ifstream or cin?
EDIT:
In other words, the following assert should always pass:
while (!IsEof(is)) {
int something;
assert(is >> something);
}
The istream class has an eof bit that can be checked by using the is.eof() member.
Edit: So you want to see if the next character is the EOF marker without removing it from the stream? if (is.peek() == EOF) is probably what you want then. See the documentation for istream::peek
That's impossible. How is the IsEof function supposed to know that the next item you intend to read is an int?
Should the following also not trigger any asserts?
while(!IsEof(in))
{
int x;
double y;
if( rand() % 2 == 0 )
{
assert(in >> x);
} else {
assert(in >> y);
}
}
That said, you can use the exceptions method to keep the "house-keeping' in one place.
Instead of
if(IsEof(is)) Input(is)
try
is.exceptions( ifstream::eofbit /* | ifstream::failbit etc. if you like */ )
try {
Input(is);
} catch(const ifstream::failure& ) {
}
It doesn't stop you from reading before it's "too late", but it does obviate the need to have if(is >> x) if(is >> y) etc. in all the functions.
Normally,
if (std::is)
{
}
is enough. There is also .good(), .bad(), .fail() for more exact information
Here is a reference link: http://www.cplusplus.com/reference/iostream/istream/
There are good reasons for which there is no isEof function: it is hard to specify in an usable way. For instance, operator>> usually begin by skipping white spaces (depending on a flag) while some other input functions are able to read space. How would you isEof() handle the situation? Begin by skipping spaces or not? Would it depend on the flag used by operator>> or not? Would it restore the white spaces in the stream or not?
My advice is use the standard idiom and characterize input failure instead of trying to predict only one cause of them: you'd still need to characterize and handle the others.
No, in the general case there is no way of knowing if the next read operation will reach eof.
If the stream is connected to a keyboard, the EOF condition is that I will type Ctrl+Z/Ctrl+D at the next prompt. How would IsEof(is) detect that?
What does the istream::getline method return?
I am asking because I have seen that to loop through a file, it should be done like this:
while ( file.getline( char*, int ) )
{
// handle input
}
What is being returned?
It returns a stream so that we can chain the operation.
But when you use an object in a boolean context the compiler looks for an conversion operator that can convert it into a type that can be used in the boolean context.
C++11
In this case stream has explicit operator bool() const. When called it checks the error flags. If either failbit or badbit are set then it returns false otherwise it returns true.
C++03
In this case stream has operator void*() const. As this results in a pointer it can be used in a boolean context. When called it checks the error flags. If either failbit or badbit are set then it returns NULL which is equivalent to FALSE otherwise it returns a pointer to self (or something else valid though you should not use this fact)).
Usage
So you can use a stream in any context that would require a boolean test:
if (stream >> x)
{
}
while(stream)
{
/* do Stuff */
}
Note: It is bad idea to test the stream on the outside and then read/write to it inside the body of the conditional/loop statement. This is because the act of reading may make the stream bad. It is usually better to do the read as part of the test.
while(std::getline(stream, line))
{
// The read worked and line is valid.
}
Look from reference. The istream returned from getline is converted to bool by implicit conversion to check success of operation. That conversion makes usage of if(mystream.getline(a,b)) into shorthand for if(!mystream.getline(a,b).fail()).
It returns the stream itself. The stream can convert (through void*) to bool indicating its state. In this example, your while loop will terminate when the stream's conversion to bool goes "false", which happens when your stream enters an error state. In your code, it's most likely to occur when there was an attempt to read past the end of the file. In short, it'll read as much as there is, and then stop.
The function returns a reference to the stream object itself, which can be used either to chain further read operations:
myStream.getline(...).getline(...);
or, because streams are implicitly convertible to void *s, in a loop or condition:
while (myStream.getline(...)) {
...
}
You can read more about this on the cplusplus.com website:
http://cplusplus.com/reference/iostream/istream/getline/
Everyone has told you what it is, now let me tell you, use the free form version
std::string line;
while(getline(file, line)) // assuming file is an instance of istream
{
//
}
Why this version? It should become immediately apparent - you pass in a std::string rather than some fixed size character buffer!