C++/istream

Advertisement


Question
QUESTION: Hello,

I'm working on a program that processes either standard in, or a file, depending on an optional command line parameter.  Simple, common situation, right?  So I'm trying to set up a reference to an istream that which references either cin, or an istream that has been constructed with a filename.  Should be a reasonable thing to do..?  Apparently not?

My problem is, as I'm sure you've guessed, that I don't know, at declaration time, whether I'll be working with cin or a file, but I have to initialize the stream reference at declaration time, somehow.  But if I set it to a stream that has been instantiated and initialized in an if block.. the stream goes out of scope when the if block ends, and I'm left with a dangling reference outside of the if block.

Can you provide an example of how to do get a reference to a stream that is set to cin if no filename has been provided, or is a stream of a given filename if a filename has been provided?

It doesn't work to pass the buck to the caller of a function or the constructor of the class, like this:

[code]
 MyClass {
    public:
       MyClass(fin = cin) : fin(fin) {}
    private:
       istream & fin;
 }
[/code]

..because then I just have the same problem at that caller's level.

This has to be a common problem with a well known solution.  I must be missing something simple and obvious, here.  Maybe instead of setting up a reference to a stream, I should be setting up a reference to a filebuffer, and then set the filebuffer to cin's filebuffer if no file is provided or something.. but then I have to dynamically allocate that filebuffer..

Is there a simple and elegant solution to this that doesn't require dealing with any dynamic allocation?


Thanks for any help,

Shavais

ANSWER: > Maybe instead of setting up a reference to a stream, I should be setting up a reference to a filebuffer,
> and then set the filebuffer to cin's filebuffer if no file is provided or something.. but then I have to
> dynamically allocate that filebuffer..
> Is there a simple and elegant solution to this that doesn't require dealing with any dynamic allocation?

The std::streambuf idea is a workable one. And you do not have to allocate it dynamically; the streambuf classes know how to manage their own memory.

For example:

#include <iostream>
#include <fstream>
#include <string>

struct myclass
{
   public:

       explicit myclass( std::istream& stm ) : in(stm) {}

       void test_it()
       {
         std::string str ;
         while( std::getline( in, str ) )
         std::cout << str << '\n' ;
       }

       // ...

   private: std::istream& in ;
};

int main( int argc, char** argv )
{
   std::streambuf* buf = std::cin.rdbuf() ;

   if( argc > 1 ) // use file instead of std::cin
   {
       static std::ifstream file( argv[1] ) ;
       buf = file.rdbuf() ;
   }

   std::istream stm(buf) ;

   myclass obj(stm) ;

   obj.test_it() ;

}


---------- FOLLOW-UP ----------

QUESTION: Hello Vijayan,

Thanks so much for your response, I'm especially grateful for the example.  I didn't even think about using a static stream.  I'm so used to thinking in the context of keeping things neatly wrapped inside class instances and the need for thread safety and such that that didn't even occur to me, but I guess that works just fine in this context.  Standard in itself, is, after all, static/global.  

Thanks for the help,
Shavais

Answer
On thinking about it later, I've realized that there is an even simpler alternative - use an arithmetic if expression while passing the stream to the constructor.

#include <iostream>
#include <fstream>
#include <string>

struct myclass
{
   public:

       explicit myclass( std::istream& stm ) : in(stm) {}

       void test_it()
       {
         std::string str ;
         while( std::getline( in, str ) )
         std::cout << str << '\n' ;
       }

       // ...

   private: std::istream& in ;
};

int main( int argc, char** argv )
{
   std::ifstream file ;

   if( argc > 1 ) file.open( argv[1] ) ;

   myclass obj( argc>1 ? file : std::cin ) ;

   obj.test_it() ;

}  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


vijayan

Expertise

my primary areas of interest are generic and template metaprogramming, STL, algorithms, design patterns and c++09. i would not answer questions about gui and web programming.

Experience

over 15 years

Education/Credentials
post graduate engineer

©2012 About.com, a part of The New York Times Company. All rights reserved.