Stringstream object errant behavior!!

Hi folks! I do need fresh pairs of eyes to look into the puzzling behavior in the member function void customerType::returnBook(...) shown below.

Just to provide some background, the function is basically supposed to delete a book's title(of type newString - a user_defined class) from the list of books borrowed from a library by a client(an object of class customerType). Upon returning a book, the reference parameter, reallyBorrowed, is supposed to be true if
the client actually borrowed the book and false if not. Function deleteNode is a member function in a linked-list base class (linkedListType) while rentedBookList(a pointer data member of class customerType) is a pointer to an object of class linkedListType. The definition of the member function is shown below:


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
void customerType::returnBook(newString title, bool& reallyBorrowed)
{
    int len;
    string str;
    stringstream myString;
    streambuf *psbuf, *backup;
    
    backup = cout.rdbuf();        //back up cout's streambuffer
    psbuf = myString.rdbuf();     //get myString's streambuffer
    cout.rdbuf(psbuf);            //assign myString's streambuffer to cout
    
    rentedBookList->deleteNode(title);   
 
    cout.rdbuf(backup);           //restore cout's original streambuffer;
       
    str = myString.str();

 //****************** PUZZLING BLOCK ****************************
    len = str.length();
    cout<<str<<" and length = "<<len<<endl;*/
 //**************************************************************

    str = str.substr(0, len-1);
    
    if (str == "Cannot delete from an empty list." || str == "Item to be deleted is not in the list.")     
        reallyBorrowed = false;  
    else
        reallyBorrowed = true;  
}



Function deleteNode has two cout statements that I do not want displayed on the screen, but rather, captured as string literals and used to produce a Boolean value, indicated by reference parameter reallyBorrowed. This base class member function's definition is shown below:


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
44
45
46
47
48
template<class elemType>
void linkedListType<elemType>::deleteNode(const elemType& deleteItem)
{
     nodeType<elemType> *current;              //pointer to traverse the list
     nodeType<elemType> *trailCurrent;         //pointer just before current
     bool found;
     
     if (first == NULL)      //Case 1: list is empty
         cout<<"Cannot delete from an empty list.\n";
     else
     {
         if (first->info == deleteItem)      //Case 2
         {
             current = first;            //in order not to lose the whole list since the first node is to be deleted (mine)
             first = first->link;        //advance pointer first to point to the next node (mine)
             if (first == NULL)          //Case 2a (mine); list had only one node
                 last = NULL;            //set last to NULL also (mine)
             delete current;             //Case 2a & 2b (mine); deletes node pointed to by current and deallocates the memory
         }
         else       //Case 3 (mine);  search the list for the node with the given info
         {
             found = false;
             trailCurrent = first;        //set trailCurrent to point to the first node
             current = first->link;       //set current to point to the second node
             
             while (!found && (current != NULL))
             {
                 if (current->info != deleteItem)
                 {
                     trailCurrent = current;
                     current = current->link;
                 }
                 else
                     found = true;
             }//end while
             
             if (found)           //if found, delete the node
             {
                 trailCurrent->link = current->link;         //Case 3a; bypassing the node pointed to by current (mine)
                 if (last == current)                        //Case 3b (mine); node to be deleted was the last node
                     last = trailCurrent;                    //update the value of last
                 delete current;                             //delete the node from the list
             }
             else                 //Case 4 (mine)
                 cout<<"Item to be deleted is not in the list."<<endl;
         }//end else
     }//end else
}


Against the backdrop of my NOT wanting to change anything in the base class code, here are my questions:

Question 1: Why is it that the member function returnBook(...) performs correctly when the two-line code enclosed in the PUZZLING BLOCK is there but doesn't when the block is left out??

Question 2: The length of the first cout string literal, when manually counted, is 33 while the second's is 38. However, I observed that the corresponding values of len, for these literals, are 34 and 39 respectively during program run! Why is this so? I was thinking it's because of them being null-terminated strings; but they can't be - since they are NOT c-strings. Please, help clarify this errant behavior here.

By the way, class customerType is NOT derived from class linkedListType.

Thank you.
Last edited on
First, if you want information from deleteNode, you should return a value from the function or throw an exception. You should NOT do what you're doing.

For instance if we changed deleteNode to look like this:
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
44
45
46
47
48
49
50
template<class elemType>
bool linkedListType<elemType>::deleteNode(const elemType& deleteItem)
{
     nodeType<elemType> *current;              //pointer to traverse the list
     nodeType<elemType> *trailCurrent;         //pointer just before current
     bool found;
     
     if (first == NULL)      //Case 1: list is empty
         return false;
     else
     {
         if (first->info == deleteItem)      //Case 2
         {
             current = first;            //in order not to lose the whole list since the first node is to be deleted (mine)
             first = first->link;        //advance pointer first to point to the next node (mine)
             if (first == NULL)          //Case 2a (mine); list had only one node
                 last = NULL;            //set last to NULL also (mine)
             delete current;             //Case 2a & 2b (mine); deletes node pointed to by current and deallocates the memory
         }
         else       //Case 3 (mine);  search the list for the node with the given info
         {
             found = false;
             trailCurrent = first;        //set trailCurrent to point to the first node
             current = first->link;       //set current to point to the second node
             
             while (!found && (current != NULL))
             {
                 if (current->info != deleteItem)
                 {
                     trailCurrent = current;
                     current = current->link;
                 }
                 else
                     found = true;
             }//end while
             
             if (found)           //if found, delete the node
             {
                 trailCurrent->link = current->link;         //Case 3a; bypassing the node pointed to by current (mine)
                 if (last == current)                        //Case 3b (mine); node to be deleted was the last node
                     last = trailCurrent;                    //update the value of last
                 delete current;                             //delete the node from the list
             }
             else                 //Case 4 (mine)
                 return false ;
         }//end else
     }//end else

     return true ;
}


then, returnBook looks like:

1
2
3
4
void customerType::returnBook(newString title, bool& reallyBorrowed)
{    
    reallyBorrowed = rentedBookList->deleteNode(title);   
 }


Question 1: Why is it that the member function returnBook(...) performs correctly when the two-line code enclosed in the PUZZLING BLOCK is there but doesn't when the block is left out??

Without line 19, len is some junk value. That junk value may cause line 23 to fail if you've compiled in debug mode and your compiler inserts code to check if uninitialized variables are used.

Question 2:The length of the first cout string literal, when manually counted, is 33 while the second's is 38. However, I observed that the corresponding values of len, for these literals, are 34 and 39 respectively during program run! Why is this so? I was thinking it's because of them being null-terminated strings; but they can't be - since they are NOT c-strings. Please, help clarify this errant behavior here.

You aren't dealing with the string literals, and the strings you get from deleteNode are not identical to them. They each have a newline appended.
Thanks indeed cire for your response. I fully acknowledge the simplicity and ease of your approach which changed the return type of function deleteNode to bool and used Boolean value returns instead of the string literals. However, the nature of the question I am solving precludes me from making any changes to a base class's member functions. That's why in my OP, I wrote
Against the backdrop of my NOT wanting to change anything in the base class code, ...

As per Question 1, I accept your answer. The reason for the program failing in this context looks so obvious now I wonder why I asked the question in the first place!

As per Question 2, you wrote:
You aren't dealing with the string literals, and the strings you get from deleteNode are not identical to them. They each have a newline appended.

Well, to a point, you're right. I intentionally left out the newline character in line 25 of function deleteNode because I initially had problems dealing with the endl manipulator at the end of the second string literal. I knew that

cout<<"Item to be deleted is not in the list."<<endl;

and

cout<<"Item to be deleted is not in the list.\n";

are technically the same, from the compiler's perspective. I just did not know that I could have the second statement stand in for the first in line 25 of function deleteNode. What I ended up doing is delete line 23 of function returnBook and used

if (str == "Cannot delete from an empty list.\n" || str == "Item to be deleted is not in the list.\n")

in line 25 of function deleteNode. The program now works fine.
Thanks indeed cire for your response. I fully acknowledge the simplicity and ease of your approach which changed the return type of function deleteNode to bool and used Boolean value returns instead of the string literals. However, the nature of the question I am solving precludes me from making any changes to a base class's member functions.

Presumably linkedListType is not a base class.

Either way, what you're doing is convoluted. A linked list type generally has some of way of iterating over it (or even a member function which will tell you if data is already in the list.) Those methods should be used in returnBook in place of what you're doing.
Topic archived. No new replies allowed.