Some General C++ Questions

I had a buddy of mine who took C# ask me some questions the other day that I just down right did NOT know the answer to. Can one of you guys help explain this to me so I don't look like a tard next time?


So, given that a class will have a pointer to memory that is allocated at run time, what member methods and/or operators will be needed to be written (as a minimum for the thing to work) and why?


How do I create a function in C++ that will have default values for parameters?
1. If you want your class to manage allocation and deallocation, you'll need to write a constructor and a destructor. However you can (but usually shouldn't) leave memory management to whoever uses your class.

2. You can initialize your members in a constructor.
So, given that a class will have a pointer to memory that is allocated at run time, what member methods and/or operators will be needed to be written (as a minimum for the thing to work) and why?

This is a loaded question and it is dependent on the situation, but I think your friend is hinting at the following necessities:

1. destructor (virtual if a base class)
2. copy constructor
3. overloaded assignment

Let's say we have the following classes:

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
//myClass.h
#include <exception>
using namespace std;

class unallocatedException: public exception
{
     virtual const char* what() const throw()
     {
          return "Pointer is unallocated";
     }
} myUnallocatedException;

class myClass
{
     private:
          int* intPtr;

     public:
          myClass()
          {
               intPtr = 0; //null ptr
          }

          void setInt(int n)
          {
               if(intPtr)
               {
                    delete intPtr;
                    intPtr = 0;
               }

               intPtr = new int;
               *intPtr = n;
          }

          int getInt()
          {
                if(!intPtr)
                {
                      throw myUnallocatedException;
                }

                return *intPtr;
          }
};


and we do the following:

1
2
3
4
5
6
7
8
9
10
#include "myClass.h"
int main()
{
     {
          myClass c;
          c.setInt(5);
     }

     return 0;
}


there will be a memory leak after c is destroyed (it got an int pointer from the heap (4 bytes) but it never deallocated it). A destructor is needed to avoid memory leaks when an instance of the class is destructed. In this case, we need the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class myClass
{
     private:
          ...

     public:
          ...

          ~myClass()
          {
               if(intPtr)
               {
                    delete intPtr;
               }
          }
};


If this class will be derived at some point, the destructor should be declared virtual so that the destructors are called in the correct order.

Now, let's say we did the following:

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
     myClass c1;
     myClass c2;

     c1.setInt(10);
     c2.setInt(20);

     c1 = c2;

     return 0;
}


This program results in undefined behavior since the assignment results in a shallow copy of intPtr (not to mention a memory leak as access to c1's intPtr is gone forever). Now, when c1 goes out of scope, c2's intPtr would be deleted. Then, when c2 goes out of scope, its intPtr would be deleted again. The same thing would happen if c2 went out of scope first (which I think would happen in the above example). To avoid double deletion we could set intPtr to zero in the destructor but there would still be a memory leak.

To fix this, we need to overload the assignment operator.

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
class myClass
{
     private:
          ...

     public:
          ...

          myClass& operator=(const myClass& other)
          {
               if(intPtr)
               {
                     delete intPtr;
               }

               intPtr = new int;
               *intPtr = *(other.intPtr);

               return *this;
          }

          ~myClass()
          {
               if(intPtr)
               {
                    delete intPtr;
               }
          }
};


There is still one more problem. Say we do this in the code:

1
2
3
4
5
6
7
8
9
int main()
{
     myClass c1;
     c1.setInt(10);

     myClass c2 = c1;

     return 0;
}


In the above example, the overloaded assignment operator isn't called, but rather c2's copy constructor is called. C++ gives all objects a default copy constructor, and guess what, its default behavior is to do a simple assignment of all the member variables. This results in a shallow copy of intPtr. A memory leak occurs similar to the above.

To fix this, we give myClass a copy constructor:

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
class myClass
{
     private:
          ...

     public:
          ...

          myClass(const myClass& other)
          {
               intPtr = new int;
               *intPtr = *(other.intPtr);
          }

          myClass& operator=(const myClass& other)
          {
               if(intPtr)
               {
                     delete intPtr;
               }

               intPtr = new int;
               *intPtr = *(other.intPtr);

               return *this;
          }

          ~myClass()
          {
               if(intPtr)
               {
                    delete intPtr;
               }
          }
};


Now, we can assign and copy construct instances of myClass and have them go out of scope without memory leaks!

How do I create a function in C++ that will have default values for parameters?

In the declaration of the function, do something like this:

int myFunc(int a=5, bool b=false);

This says that a call to myFunc, if given no parameters, would result in a being given the default value of 5 and b being given the default value of false. If in a call to myFunc, a is specified but b is not, b would be given the default value of false and a would be given whatever is passed in.

The definition of the function would look just like all other functions:

1
2
3
4
int myFunc(int a, bool b)
{
     ...
}
Last edited on
Topic archived. No new replies allowed.