Search code examples
c++stringstreamostream

Passing stringstream as ostream&, no content being read


I'm coding an assignment where, basically, I have a client and server communicating. For this, I'm using a stringstream in the server side to process the requests (that come in the form of strings) and help build a string response. The server side holds an object (FileManager) that contains several MultimediaFile objects, each with information about themselves. This information can be printed through a method, of which one of the parameters is an ostream&.

To get the request from the client, the stringstream works just fine, but when I pass it to the method, for some reason it doesn't read the content (whereas if I pass std::cout it works just fine). I'm thinking it has something to do with the way stringstream uses the << operator to read information, but I'm unsure how to correct this.

I know I could simply store the information I need about the object in a string or something like that (instead of using ostream&), but the professor wants the method to print directly to the passed ostream, and not return a string.

Here's the code:

bool processRequest(TCPServer::Cnx& cnx, const string& request, string& response)
{
bool changeData = false;
if (request == "delMedias" || request == "delGroups") changeData = true;

TCPServer::Lock lock(cnx, changeData);

cerr << "request: '" << request << "'" << endl;
string operation = "";
string filename = "";
stringstream iss;

iss.str(request); //next few lines get request info, works just fine!

if (iss.rdbuf()->in_avail() != 0)
    iss >> operation;
if (iss.rdbuf()->in_avail() != 0)
    iss.get();
if (iss.rdbuf()->in_avail() != 0)
    getline(iss, filename);
iss.str("");


if (operation.size() == 0 || filename.size() == 0) return false;

response = "";

if (operation.compare("print") == 0)
{
        filem.showFile(filename, iss); //Problem here!!!!
        if (iss.rdbuf()->in_avail() != 0) //iss is always empty
        {
            response = iss.str();
            response = "Print info: " + response;
        }
        else
            response = "No info received!";
}
else if (operation.compare("play") == 0)
{
        filem.playFile(filename);
        response = "File played!";
}
else
    response = "Operation not valid";

cerr << response << endl;

return true;
}

TCPServer is a class provided by the professor to make things easier, but basically the client sends a string request and, at the end of this function, receives a string response from the server. filem is the FileManager class object, and here's the code for the showFile method:

void FileManager::showFile(string name, ostream& s)
{
    if (mfiles.find(name) != mfiles.end())
        mfiles[name]->printFile(s);
}

mfiles is a map of string to MultimediaFile* (specifically std::shared_ptr of MultimediaFile, but anyway). Basically, this code checks if there is a file named name, and if so, calls the method printFile(s) where s here would be the stringstream. Here's the method's code:

void MultimediaFile::printFile(ostream& s) const
{
    s << "File name: " << name << "\tFilepath: " << filepath << "\n";
}

name and filepath are instance variables of the MultimediaFile class. So, yeah, here I was expecting my stringstream to receive this information, which would then be used to build the response string in the main part of the code, just after the method call. That's not what happens however, and the stringstream is always empty (and since this works with std::cout, then the problem is not the data in the MultimediaFile object).

Again, I would say stringstream behaves differently than cout when getting data through the << operator, but I couldn't find any information that would help me in this case... Does anybody have an idea?

If there's any other information you need please let me know. And thanks in advance!


Solution

  • So, apparently I found a solution.

    To test some things, I tried creating a separate bit of code just to check how the method would behave with the stringstream. And... it worked. The only difference between my separate tests, and the problem itself was that, in my program, the stringstream was being used to get data from the request string before being passed to the method to get data from there. So, what I did is, I created a second stringstream that was passed to the method... and it worked.

    Basically, this is what I changed (the rest of the code is the same as the original post):

    response = "";
    stringstream iss2; //create another stringstream
    
    if (operation == "print")
    {
            filem.showFile(filename, iss2); //use it instead of the first one
            if (iss2.rdbuf()->in_avail() != 0)
            {
                response = iss2.str();
                response = "Print info: " + response;
            }
            else
                response = "No info received!";
    }
    

    I have no idea why the first stringstream doesn't work; maybe one of the methods I used to get the request information (str(), get(), getline() or the >> operator) change the state of the stringstream so that it doesn't accept new information? I don't know, just random thoughts.

    But anyway, this works, so I'm happy for now...

    P.S.: I also changed the operation.compare("print") to operation == "print". I couldn't remember the reason I used compare, and I got no warnings during compilation like I thought I had, so, yeah...