Search code examples
c++vectorostreamistream

Need help in completing a function for sorting k sorted streams


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?


Solution

  • 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!