Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird constructor in C++ class

On Saturday I have an exam and I'm going through the past papers and I've encountered question according to C++ code:

class Car {
     char *LicencePlate;
     int age;
public:
     Car(const Car &); //this declaration
     ~Car();
}

What is the purpose of the declaration on line 5? In general what functionality should the implementation of a declaration of this nature provide? Write the code required for the implementation of the declaration on line 5 as it would appear in the Car.cpp file given the information provided.

like image 657
Kasia Fijołek Avatar asked May 23 '12 21:05

Kasia Fijołek


People also ask

Why colon is used with constructor in C++?

It initializes members before the body of the constructor executes. Save this answer. Show activity on this post. It's called an initialization list.

What does Colin mean in C++?

In C++, the colon ':' operator, to my understanding, is used for inheritance. However, inside classes, I have seen it used presumably for other reasons. What is this operator used for? - Open in App. In C++, the colon ":" operator, to my understanding, is used for inheritance.


3 Answers

It is a copy constructor, it's purpose is to make an exact copy of the object which was given as a parameter.

I will leave it to you to decide how best to do that.

like image 27
Ben Avatar answered Oct 26 '22 13:10

Ben


Let's go through this.

As you can tell from the name, that's a constructor. Because it takes a parameter a reference to an object of the same type, it's a copy constructor (C++ nomenclature).

As you know (or not), if you don't have a copy constructor, the compiler will generate one for you. The compiler generated copy constructor does a shallow copy.

Why you want to implement your own:

class Car {
     char *LicencePlate;
public:
     Car(char* plate, int size)
     {
        LicencePlate = new char[size];
        strcpy(LicencePlate, plate);
     }
     ~Car()
     {
        delete[] LicencePlate;
     }
};

I've modified your class a bit to better explain. Your class manages memory now. It allocates memory for LicencePlate. This is the scenario where you don't have a copy constructor. Say you do:

Car a("abc",3);

The compiler generated copy constructor is called with:

Car b(a);

But remember, this only does a shallow copy. So, actually, a.LicencePlate == b.LicencePlate. Can you see anything wrong with that?

When a goes out of scope, the destructor is called, and a.LicencePlate is deleted. But then you run into undefined behavior when b goes out of scope, because b's destructor will try to delete the same memory (remember, the two pointer point to the same memory because a shallow copy was created).

To avoid this, you define your own copy constructor:

class Car {
     char *LicencePlate;
     int sz;
public:
     Car(char* plate, int size)
     {
        LicencePlate = new char[size+1]();
        strcpy(LicencePlate, plate);
        sz = size;
     }
     Car(const Car& other)
     {
        LicencePlate = new char[other.sz+1]();
        sz = other.sz;
        strcpy(LicencePlate, other.LicencePlate);
     }
     ~Car()
     {
        delete[] LicencePlate;
     }
};

The rule of three means you should implement an assignment operator (you already have a copy constructor and a destructor). The motivation behind this is the same, only the problem replicates when you assign instead of initialize:

Car a("abc",3);
Car b;
b = a; //assignment - operator= is called

Now we're safe. b, when copied, will allocate new memory to hold the licence plate, so the double-delete can't occur.

I changed the code to demonstrate the point but you'll still have to put logic in there yourself.

like image 55
Luchian Grigore Avatar answered Oct 26 '22 15:10

Luchian Grigore


That's a copy constructor declaration. It takes a reference to a constant Car, meaning you can read the passed in value, but can not (without dodgy casts) write it. This is just the canonical way of creating a new object by copying the original. You will probably want to do a strdup as part of the implementation.

like image 2
Matthew Flaschen Avatar answered Oct 26 '22 14:10

Matthew Flaschen