I came across this post which explains the copy and swap idiom. However I could not find this idiom applied to classes that have base classes. Following is my attempt of a copy-swap idiom applied to class constructors and assignment operators. In the following code class employee
inherits from class human
- The constructors and assignment operators of both the classes are quite similar in manner. I am more interested in making this a generic class. If you have solid suggestions about exception safety please let me know. I would like to keep the code to a minimum to serve as a guiding principal for further classes. I also understand that using a char *
is not recommended for a C++ project however most of the projects that I have come across use a char*
here and there.
#include <iostream>
#include <cstring>
class details
{
std::string optional_info;
};
class human
{
public:
char *blood_type=nullptr;
std::string dob = "";
details* di = nullptr;
//This is the swap method
void swap(human& lhs , human& rhs)
{
std::swap(lhs.blood_type , rhs.blood_type);
std::swap(lhs.dob , rhs.dob);
std::swap(lhs.di , rhs.di);
}
public:
//Regular constructor
human() {/*...*/}
human(const human& f)
{
//Copy the blood_type char pointer
if(f.blood_type != nullptr) {
blood_type = new char[std::strlen(f.blood_type) + 1];
strcpy(blood_type, f.blood_type);
}
//Copy the string
this->dob = f.dob;
//Copy the object detail
this->di = new details(*(f.di));
}
//Assignment operator
human& operator=(human& f)
{
if(this != &f) //Make sure they are not the same
{
human temp = f; //Call the copy constructor
swap(*this,temp); //Swap the values;
}
return *this;
}
//Move copy constructor
human(human&& f)
{
swap(*this , f);
}
//Move copy constructor
human& operator=(human&& f)
{
swap(*this , f);
return *this;
}
~human()
{
if(blood_type!=nullptr)
delete blood_type;
if(di!=nullptr)
delete di;
}
};
class employee : public human
{
public:
char *duty=nullptr;
std::string title="";
details* detail=nullptr;;
//This si the swap method
void swap(employee& lhs , employee& rhs)
{
std::swap(lhs.duty , rhs.duty);
std::swap(lhs.title , rhs.title);
std::swap(lhs.detail , rhs.detail);
}
public:
//Regular constructor
employee() {/*...*/}
//Copy constructor
//Since we provided a custom copy constructor we should also
//call the copy constructor of the base class using initialization list
//If we do not do that the regular constructor of base class will be called.
employee(const employee& f) : human(f) //This will call the copy constructor of base class
{
//Copy the address char pointer
if(f.duty != nullptr) {
duty = new char[std::strlen(f.duty) + 1];
strcpy(duty, f.duty);
}
//Copy the string
this->title = f.title;
//Copy the object detail
this->detail = new details(*(f.detail));
}
//We need to copy the base class too.
//Assignment operator
employee& operator=(employee& f)
{
if(this != &f) //Make sure they are not the same
{
employee temp = f; //Call the copy constructor
human::operator=(temp); //<---Design question regarding this at end.
swap(*this,temp); //Swap the values;
}
return *this;
}
//Move copy constructor
employee(employee&& f) : human( std::move( f)) //call move constructor of base class
{
//Important
//Now f is an lvalue (since it has a name) that is holding an rvalue.
swap(*this , f);
}
//Move copy constructor
//Rvalue reference to hold temporaries as parameter
employee& operator=(employee&& f)
{
human::operator=(std::move(f)); //Call assignment operator of base classa
swap(*this , f);
return *this;
}
~employee()
{
if(duty!=nullptr)
delete duty;
if(detail!=nullptr)
delete detail;
}
};
Questions:
Does this class comply with the copy-swap idiom? Is anything missing or overlooked?
I noticed that the assignment operator in the above class could use improvements. For instance, first it creates a deep copy of the object using its copy constructor (during which a copy of the base class is made) after that the following call is made:
human::operator=(temp) ;
This statement calls the copy assignment operator of the base class which in return makes another deep copy using its own copy constructor. I wanted to know if there was a better way of accomplishing this.