Strange runtime Error

Hello,

I've been trying to debug this code for some time now and I can't figure out exactly where it's breaking. Here's the execution so far:

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
51
52
53
#include "myqueue.h"
#include "robot.h"
#include <iostream>
using namespace std;

const int K_NUM_OFFERED = 4,                            // Number of services
          K_TIMES[K_NUM_OFFERED] = {23, 14, 8, 20};     // time constants
const string K_TYPES[K_NUM_OFFERED] = {"paint",
                                       "metalwork",
                                       "oilbath",
                                       "memwip"};       // type constants

int main()
{
  // Variable Declarations
  queue<robot> the_line;
  int iTime;
  string sName;
  service shop[K_NUM_OFFERED];

  // Greeting
  cout << endl << "Welcome to Mom's Friendly Robot Inc. Maintanence Division!"
       << " We'll decommission, " << endl << "I mean fix, your robot right"
       << " away!" << endl;

  // Setting variables
  for (int i = 0; i < K_NUM_OFFERED; i++)
    shop[i].set_typ(K_TYPES[i]);

  // Input
  do
  {
    // Variable Declarations
    robot dude;
    string sService;
    int iNumServices;

    // Input name
    cin >> sName;
    if (sName != ".")
    {
      dude.set_name(sName);

      // Input services requested
      cin >> iNumServices;
      for (int i = 0; i < iNumServices; i++)
      {
        cin >> sService;
        dude.set_serv(sService);
      };

      // Get in line
      the_line << dude;


at which point execution transfers to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class T>
  void queue<T>::operator<<(const T& stuff)
  {
    // Variable Declarations
    queue<T>* new_item;
    new_item = new queue<T>;

    // Link new_item
    if (m_next == NULL)
      new_item->m_next = new_item;
    else
    {
      new_item->m_next = m_next->m_next;
      m_next->m_next = new_item;
    }

    // "Move" new_item to the back of the list
    m_next = new_item;

    // Put value in new_item
    new_item->m_data = stuff;


This all works great if you're only working with objects like queue<T>. However, the implementation I'm using involved building a class robot that has members m_name (string) and m_services (queue<string>). As such, when the above code is actually run execution switches to:

1
2
3
4
robot& robot::operator=(const robot& rhs)
{
  m_name = rhs.m_name;
  m_services = rhs.m_services;


and then execution switches to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template <class T>
  queue<T>& queue<T>::operator=(const queue<T>& rhs)
  {
    // Variable Declarations
    const queue<T>* current = (rhs.m_next)->m_next;
    const queue<T>* last = rhs.m_next;

    // Empty queue
    if (!isEmpty())
      clear();

    // Assign all values in rhs
    while (current->m_next != last)
    {
      *this << current->m_data; // Point 1
      current = current->m_next;
    }

    // Deallocate Memory
    current = NULL;
    last = NULL;

    return *this;
  }


At point 1 which I have commented, execution moves back to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <class T>
  void queue<T>::operator<<(const T& stuff)
  {
    // Variable Declarations
    queue<T>* new_item;
    new_item = new queue<T>;

    // Link new_item
    if (m_next == NULL)
      new_item->m_next = new_item;
    else
    {
      new_item->m_next = m_next->m_next;
      m_next->m_next = new_item;
    }

    // "Move" new_item to the back of the list
    m_next = new_item;

    // Put value in new_item
    new_item->m_data = stuff;
    return;
  }


After which, execution moves back to the queue<T>::operator= and should finish and after that execution should move to robot::operator= and should finish and then operation should move back to queue<T>::operator<< and should finish. Finally, execution should move back to main and should process to finishing the if statement and while loop. However, as far as I can tell, execution stops for some reason and I cannot find where it happens or why, which makes debugging impossible.

Here's the simplified execution:

Call queue<robot>::operator<<(dude)
Call robot::operator=(dude)
Call queue<string>::operator=(dude.m_services)
Call queue<string>::operator<<(dude.m_services)

I'm thinking that the queue containing dude.m_services is being lost somewhere but I'm not sure why.

Update: I'm reasonably sure that the execution is getting stuck in an infinite loop somewhere but I'm not sure why.

Any help you could offer would be appreciated.

Thanks
Last edited on
void queue<T>::operator<<(const T& stuff)

You are sending it a const reference. This means that the T obeject behaves as it normally would. If you don't want to have that happen, do this on that last line:

&stuff;
So instead of

void queue<T>::operator<<(const T& stuff)

you're saying it should be just

void queue<T>::operator<<(T& stuff)

correct?
new_item->m_data = &stuff;

Because you are passing T by reference, the compiler treats it as an object. When it goes to link the code, it sees an object, and not a pointer, so it calls the operator.

By assigning the address of the T type, the compiler knows to create an assignment to the pointer, and not call the copy constructor.
But wouldn't that result in a shallow copy?

Furthermore, it seems that it now results in an error, as the code now tries to assign a pointer to a string to a string when it runs through the queue embedded within the queue.

 
myqueue.hpp:38:5: error: invalid conversion from const std::basic_string<char>* to char [-fpermissive]


and I'm not sure how I would go about fixing that.
Last edited on
Anyway, I changed my code for debugging purposes to

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
template <class T>
  void queue<T>::operator<<(const T& stuff)
  {
    // Variable Declarations
    queue<T>* new_item;
    new_item = new queue<T>;
    cout << endl << "if (m_next == NULL)";
    // Link new_item
    if (m_next == NULL){
      cout << endl << "new_item->m_next = new_item;";
      new_item->m_next = new_item;}
    else
    {
      cout << endl << "new_item->m_next = m_next->m_next;";
      new_item->m_next = m_next->m_next;
      m_next->m_next = new_item;
    }
    cout << endl << "m_next = new_item;";
    // "Move" new_item to the back of the list
    m_next = new_item;
    cout << endl << "new_item->m_data = stuff;";
    // Put value in new_item
    new_item->m_data = stuff;
    cout << endl << "return;";
    return;
  }


and the output was

dude.set_name(sName);
if (m_next == NULL)
new_item->m_next = new_item;
m_next = new_item;
new_item->m_data = stuff;
return;
dude.set_serv(sService);
the_line << dude; - begin
if (m_next == NULL)
new_item->m_next = new_item;
m_next = new_item;
new_item->m_data = stuff;
if (m_next == NULL)
new_item->m_next = new_item;
m_next = new_item;
new_item->m_data = stuff;
return;
return;

The reason the operator<< function gets called twice is because of the queue object within the robot object which results in a queue in a queue. However, it looks like both statements are returning so I'm not sure what's wrong.
Ok, so apparently the operator>> isn't actually executing the return statement so execution is just sitting somewhere before the return statement.
The issue has been fixed. At the end of execution, the clear() function was called, which resulted in an infinite loop because the clear function wasn't deleting the last element so there was a memory leak, which lead to a false return case and an infinite loop (as mentioned earlier). Fixing it was incredibly easy and the code looks 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
template <class T>
  void queue<T>::operator>>(T& item)
  {
    // Variable Declarations
    queue<T>* temp;
    T data;

    if (m_next != NULL)
    {
      // Assignment
      temp = m_next->m_next;
      data = temp->m_data;

      // Link past temp
      if (m_next != m_next->m_next)
        m_next->m_next = temp->m_next;
      else
        m_next = NULL;
    }
    else
      cout << "PANIC : ERROR in Dequeue Operator!!! Queue is empty!" << endl;

    // Destroy temp
    delete temp;
    temp = NULL;

    item = data;
  }
Topic archived. No new replies allowed.