Queue issues!

Hi guys,

I have the short program below that reads three lines of strings from a text file. I have two cases of confounding results!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <fstream>
#include <queue>
using namespace std;

void loadFile(ifstream& inp, queue<string>& qList);

int main()
{
    queue<string> queueList; 
    ifstream infile;
    infile.open("Spanish_MustKnow2.txt");
    
    cout<<"Before loading queue, queueList.size() = "<<queueList.size()<<endl<<endl<<endl;
    
    loadFile(infile, queueList);
    
    cout<<"After loading queue, queueList.size() = "<<queueList.size()<<endl<<endl<<endl;
    
    while (!queueList.empty())
    {
        cout<<queueList.front()<<endl;  
        queueList.pop();      
		cout<<"queueList.size() = "<<queueList.size()<<endl;
    }
    
    cout<<endl<<endl;
    // wait until user is ready before terminating program
    system("PAUSE");
    return 0;
}


void loadFile(ifstream& inp, queue<string>& qList)
{
    string str;
    
    while(inp)
    {
        getline(inp, str);
        qList.push(str);
    }
}


Here is the text file (Spanish_MustKnow2):
la casa de amiga esta a otro lado -------------- my friend's house is on the other side                              la sede de los Olimpiadas 2016 es Brasil ------ the host of the Olympics
no tengo casa ---------------------------------- I don't have a house                                                                      donde esta tu carro ------ where is your car
a quien te refieres anoche --------------------- who are you referring to last night                                               puedes ayudarme esta noche ------ you can help me tonight




Case A:
If I don't press the ENTER key at the end of the text file (i.e. after the last string "tonight," I have the output below:

Before loading queue, queueList.size() = 0


After loading queue, queueList.size() = 4


la casa de amiga esta a otro lado -------------- my friend's house is on the other side                              la sede de los Olimpiadas 2016 es Brasil ------ the host of the Olympics
queueList.size() = 3
no tengo casa ---------------------------------- I don't have a house                                                                      donde esta tu carro ------ where is your car
queueList.size() = 2
a quien te refieres anoche --------------------- who are you referring to last night                                               puedes ayudarme esta noche ------ you can help me tonight
queueList.size() = 1
a quien te refieres anoche --------------------- who are you referring to last night                                               puedes ayudarme esta noche ------ you can help me tonight
queueList.size() = 0


Press any key to continue . . .



Case B:
However, if I press the ENTER key at the end of the text file, I have the output below:

Before loading queue, queueList.size() = 0


After loading queue, queueList.size() = 4


la casa de amiga esta a otro lado -------------- my friend's house is on the other side                              la sede de los Olimpiadas 2016 es Brasil ------ the host of the Olympics
queueList.size() = 3
no tengo casa ---------------------------------- I don't have a house                                                                      donde esta tu carro ------ where is your car
queueList.size() = 2
a quien te refieres anoche --------------------- who are you referring to last night                                               puedes ayudarme esta noche ------ you can help me tonight
queueList.size() = 1

queueList.size() = 0


Press any key to continue . . .



Here are my questions:
1. Why on earth are there 4 elements in the queue when I only read in 3?
2. Why is the last line repeated in Case A?
3. The blank (white space) in the result of Case B (i.e. the empty line before "queueList.size() = 0"), is that indicative of the newline character?

Looking forward to your responses. Thx.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
void loadFile(ifstream& inp, queue<string>& qList)
{
    std::string str;
    
    // while(inp) // check stream state *before* attempted input
    while( getline(inp, str) )  // canical: check stream state *after* attempted input
    {
        // getline(inp, str); // the attempted input may fail (typically, at end of file)
                              // but we are not checking the stream state for input failure
                                    
        qList.push(str); 
    }
}


Exploiting move semantics, copy-elision (C++11):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <fstream>
#include <queue>

std::queue<std::string> loadFile( std::ifstream&& inp ); // file streams are moveable

int main()
{
    auto queueList = loadFile( std::ifstream( "Spanish_MustKnow2.txt" ) ); // transfer ownership of the stream

    while (!queueList.empty())
    {
        std:: cout << queueList.front() << '\n' ;
        queueList.pop();
	std::cout << "queueList.size() = " << queueList.size() << '\n' ;
    }

    std::cout << "\n\n" ;
}

std::queue<std::string> loadFile( std::ifstream&& inp )
{
    std::queue<std::string> result ;

    std::string str;
    while( std::getline(inp, str) ) result.push( std::move(str) ) ; // move str into result

    return result ; // enble copy elision (move if copy is not optimised away)
}

Last edited on
Thx JLBorges. The problem I was having has been resolved!
I want to believe that you meant canonical instead of "canical" in line 6 of your first code block.

I don't think I'd seen the "move" concept used to read in a file the way you did in the second code block. Just a few questions, please:

-- Is this more efficient than the conventional method I used?

-- While I realize that you are using loadFile as a value-returning function here, how is the input file stream an rvalue reference in this case? Coincidentally, I just happened to be reading yesterday(before my OP) that move constructors/assignments require an rvalue reference as parameter.

-- In line 26, why are you using std::move again when you could have just pushed str directly into the queue object, result without it?

-- In line 28, you wrote:
... (move if copy is not optimised away)
The optimization to which to refer, is this onus on the compiler or the programmer? If it's on the programmer, how can this be done?

Looking forward to your reply. Thx.

> I want to believe that you meant canonical instead of "canical" in line 6 of your first code block.

Yes.


> Is this more efficient than the conventional method I used?

Optimisers are quite clever these days; so it probably won't be more machine efficient.
Arguably it is more programmer efficient.


> how is the input file stream an rvalue reference in this case?

In loadFile( std::ifstream( "Spanish_MustKnow2.txt" ) );,
the expression std::ifstream( "Spanish_MustKnow2.txt" ) initializes an anonymous temporary object.
The value category of such an expression is prvalue ("pure" rvalue).


> In line 26, why are you using std::move again

The value category of the expression str is lvalue, the overload of push which accepts an lvalue would copy the object.
http://en.cppreference.com/w/cpp/container/queue/push

Note: result.push( std::move(str) ) ; and then reusing str works because objects of types defined by the standard library (with a few exceptions which are explicitly stated) are guaranteed to be in a valid usable state even after they have been moved from.


> The optimization to which to refer, is this onus on the compiler or the programmer?

C++17 compilers are required to elide the copy.

Prior to C++17, copy elision is permitted, but not mandated (in practice, every compiler implements it).
Topic archived. No new replies allowed.