memory leak + copy constructor & assignment for Queue

I ran valgrind on my homework, and there's a memory leak somewhere. I think it's in my constructor.

Also, how would I start with copy constructor and assignment?

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  #ifndef queue_class
#define queue_class

#include <iostream>
using namespace std;

//template class for Queue
template <class hw12>
class Queue
{
private:
    hw12 *a;
    int head, tail;
    int size;
    int max_size;

public:
    //parameterized constrcutor
    //precondition: parameter must be a positive integer
    //postcondition: creates an object Queue
    Queue(int n)
    {
        a = new hw12[n];
        max_size = n;
        head = 0;
        tail = -1;
        size = 0;
    }
    //function to insert element in queue
    //precondition: parameter must agree with the object/template data type
    //postcondition: inserts element into the object
    //tests if queue is full
    void enqueue(hw12 value)
    {
        if (is_full())
        {
            cout << "1A - Invalid insertion; queue is full" << endl;
            return;
        }
        tail = (tail + 1) % max_size;
        a[tail] = value;
        cout << "Inserted element: " << value << endl;
        size++;
    }
    //function to remove element from queue
    //precondition: a constructor must be instantiated
    //postcondition: removes an element from the object
    //tests if queue is empty
    hw12 dequeue()
    {
        hw12 temp = hw12();
        if (is_empty())
        {
            cout << "1B - Queue is empty" << endl;
            return temp;
        }

        temp = a[head];
        head = (head + 1) % max_size;
        size--;
        cout << "Removed element: " << temp << endl;
        return temp;
    }
    //function to get the front element from queue
    //precondition: a constructor must be instantiated
    //postcondition: points to the front of the queue
    //tests if queue is empty; if so, program terminates
    hw12 front()
    {
        if (is_empty())
        {
            cout << "1C - Queue is empty" << endl
                 << "Terminated" << endl;
            exit(-1);
        }
        return a[head];
    }
    //function to check if the queue is full
    //precondition: a constructor must be instantiated
    //postcondition: checks if queue is full
    bool is_full()
    {
        if (size == max_size)
            return true;
        else
            return false;
    }
    //function to check is queue is empty
    //precondition: a constructor must be instantiated
    //postcondition: checks if queue is empty
    bool is_empty()
    {
        if (size == 0)
            return true;
        else
            return false;
    }
    //function to get the size of the queue
    //precondition: a constructor must be instantiated
    //postcondition: returns queue size
    int Size()
    {
        return size;
    }
};

#endif // queue_class 
Last edited on
Hello totoo,

In your overloaded ctor you use "new" to create memory, but where do you use "delete" to free the memory created?

Since you have an overloaded ctor you may also need to write a default ctor as the compile will not longer provide a default ctor.

Using using namespace std; in a header file is a problem waiting to happen, but you will figure that one out the hard way.

Andy
Handy Andy wrote:
Using using namespace std; in a header file is a problem waiting to happen, but you will figure that one out the hard way.


If you don't want to bother with std::, just declare using namespace std locally, within the scope you want it to apply. More about this here [1].

totoo wrote:
Also, how would I start with copy constructor and assignment?

I'm also learning about copy constructor and copy assignments. They're deceptively simple.

You define a copy constructor by overloading your user class ctor to take a reference of itself. Usually, the reference is const because when you copy an object, you wouldn't normally change the copied object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Queue {
    int size;
    std::vector<int> stuff; 
    Queue(int n) {...}
    
    // Copy constructor
    Queue(const Queue& queueThatsCopied) 
        : size(queueThatsCopied.size)
    {
        // In this context, `this` refers to the copy that needs to be initialized and queueThatsCopied refers to the object being copied (the right of the assignment).  
        this->stuff = queueThatsCopied.stuff; // Invoke std::vector<int>'s copy-constructor
        // Do other stuff to initialize the copy
    }

    // Copy assignment
    Queue& operator=(const Queue& rhs) {...}

    // Move assignment
    Queue& operator=(const Queue&& rhs) {...}
};



Copy constructors get called in contexts where your objects get copied (implicitly or explicitly) such as:
1. When you pass a parameter in by value (the variable in the calling scope gets copied to the parameter variable in the function scope).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person
{
public:
    Tea tea;
}

main() 
{
    Person drinker = Person("Alice");
    MakeTea(drinker);
}

static void MakeTea(Person teaDrinker)
{
    // Person class' copy constructor is invoked to obtain a copy of `drinker` which is then assigned to teaDrinker
    teaDrinker.tea = Tea("Jasmine Tea"); // Calling scope does not receive this Tea
    // Destructor for teaDrinker gets called. 
}


2. When you return a variable with function scope by value (the variable in the function scope gets copied to a variable (or to an R-value) in the calling scope).
1
2
3
4
5
6
7
8
9
10
11
12
13
main() 
{
    Tea myTea = MakeTea(); // Returns L-value which is then assigned to myTea
    CoolTeaByBlowing(MakeTea()); // Returns product as R-value which is then passed to CoolTeaByBlowing()
}

static Tea MakeTea()
{
    Tea product = Tea.MakeUserTea();
    return product; // Invokes Tea class' copy constructor
                             // product is copied to myTea
                             // Tea class' destructor is invoked for product 
}

3. When you assign an object to another variable:
1
2
3
 
Foo f1("Foo1");
Foo f2 = f1; // Invokes Foo copy constructor (user-defined, if specified, otherwise default) 


Yeah, I'm not here to provide a tutorial but that's what I've learned by writing some sample code.

Copy assignment is an operator overload that you define for a class that allows you to specify what happens when you assign one object to another:
1
2
3
4
Queue q1{...initialize}
Queue q2{...initialize}
q1 = q2; // Invokes copy assignment operator
Queue q3 = DoStuffThatReturnsAQueue();  // This method returns an R-Value, a Queue. The '=' invokes move assignment operator 

There are two ways to define copy assignment and they're distinguished based on whether you copy-assign an L-Value or R-Value. The copy-assignment for an R-value is called move assignment see [2, @10:53].

Copy assignments require you to know about L-Values and R-Values, see [2, @8:39-10:33, @10:45], [3].

[1] https://www.youtube.com/watch?v=4NYC-VU-svE
[2] https://www.youtube.com/watch?v=St0MNEU5b0o
[3] https://www.youtube.com/watch?v=BvR1Pgzzr38
Last edited on
If you don't want to bother with std::, just declare using namespace std locally, within the scope you want it to apply. More about this here [1].

Flogging a dead horse again (briefly):

There exist strong technical arguments against using namespace std but barely anything in favor of it. If you are a student, I strongly advise against using namespace in most cases unless you enjoy submitting code that does not compile on your professor's machine.

Using qualified names (i.e., typing std::) allows unqualified names to indicate intentional uses of ADL. Some consequences of using namespace - specifically, unintended ADL - trip up even consummate experts to the degree that these issues are a recurring topic of discussion within the ISO C++ committee.

Typing std:: reduces the risk of publishing incorrect code. The decision should be easy.
Last edited on
Topic archived. No new replies allowed.