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);
}
Related
I am working on my assignment and need help in completing the following function. I have been provided with the following signature:
void merge(const std::vector<istream>& inputStreams, ostream& o);
The function is supposed to take k integer streams as input and sort them and store the result in an ostream object.
I have completed the function definition but the problem is I cannot test the function by providing it the input (ie: vector of istream objects). If I try to pass the function a vector of istream objects, the compiler throws too many errors for me to debug.
Here is the function definition:
void merge( vector<istream>& inputStreams, ostream& o){
vector<long long int> input_vec;
long long int input_vec_size = inputStreams.size();
for(int i=0; i<input_vec_size;i++)
{
long long int temp;
while(inputStreams[i]>>temp)
{
input_vec.push_back(temp);
}
}
sort(input_vec.begin(),input_vec.end());
for(int i=0;i<input_vec.size();i++)
{
o<<input_vec[i];
}
}
And to pass a vector of istream objects i did the following:
int main()
{
//ifstream a1,a2,a3,a4;
filebuf fb1,fb2,fb3;
fb1.open("fb1.txt",ios::in);
fb2.open("fb2.txt",ios::in);
fb3.open("fb3.txt",ios::out);
istream a1(&fb1);
istream a2(&fb2);
ostream out(&fb3);
vector<istream> inp;
inp.push_back(a1);
inp.push_back(a2);
merge(inp,out);
}
can anyone help me?
For starters, it's fairly unusual to see the type istream being used as the actual type of an object. The reason for this is that istream is meant to be used as a base class, and those base classes are what more often get used. For example, you'll see variables of type istringstream or type ifstream much more regularly than just plain old istream. It's not wrong, per se, to have a variable that's an honest-to-goodness istream, but it is unusual.
Typically, if you wanted to work with a function that manipulated some sort of input stream, you'd structure it so that it either took in a reference to the istream or a pointer to the istream. That's the general C++ way of handling polymorphic types.
In your case, the fact that you're trying to use a vector<istream>, regardless of whether the code will compile or not, should therefore make you pause a minute to think about whether you're doing the right thing. It's entirely possible that, yes, you indeed do have a bunch of istream objects, and those objects aren't istringstreams or ifstreams. But more probably, what you were aiming to do here was say "I take in some list of input streams, and I don't really care what kind of input streams they are as long as they inherit from istream."
If that's what you're hoping to do, there are several ways you could address this. Perhaps the easiest is to change vector<istream> to vector<istream *> (or perhaps vector<shared_ptr<istream>>, depending on context). That would mean "I'd like to take as input a list of streams, and since I can't say for certain what specific type each of those streams will be, I'll just have the client give me pointers to each of them." That's going to require you to make some changes to your code so that, as you access the elements of the vector, you treat them as pointers rather than as actual, honest-to-goodness istream objects. For example, the line
while (inputStreams[i] >> temp) { ... }
might need to get rewritten as
while (*inputstreams[i] >> temp) { ... }
to explicitly dereference the pointer.
The other question you asked was how to test this code at all, and that's a separate step. Remember, it's fairly unusual to create objects of type istream, so you'd probably want to make either objects of type istringstream or ifstream. Here's an example of how you might make a few streams and then pass them into your function:
istringstream stream1("137 2718");
istringstream stream2("27 182 818");
istringstream stream3("3 14 15 92 653");
merge({ &stream1, &stream2, &stream3 }, cout);
Here, rather than declaring a local variable of type vector<istream *>, we just use a brace-initializer to say "please make me a vector out of these pointers."
From the sample code you've provided it looks like you want to read data from a bunch of files. Here's how you might do that. Rather than making filebuf objects and wrapping them in istreams, which is legal but fairly uncommon, we'll just use ifstream:
ifstream stream1("fb1.txt");
ifstream stream2("fb2.txt");
ifstream stream3("fb3.txt");
vector<istream *> inputs;
inputs.push_back(&stream1);
inputs.push_back(&stream2);
inputs.push_back(&stream3);
merge(inputs, cout);
Hope this helps!
istream is not copyable or moveable, hence you can't make a vector of istreams. Try using std::vector <std::istream *> instead (and modify your code accordingly).
Live demo: https://wandbox.org/permlink/20I2VQqsRI8ofaxP
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 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!
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.