Why do we need the copy and swap idiom in C++ ? But let me ask a question what is copy and swap idiom in c++ ?  Let us take an example to understand.

#include <iostream>
#include <string.h>

class employee_record {

private:
        int id;
        char* name;

public:
        employee_record(char* name_, int id_) {
                id = id_;
                size_t size = strlen(name_) + 1;
                name = new char[size];
                strncpy(name, name_, size);
        }

        virtual ~employee_record() {
                delete[] name;
        }
        void print();
};

void employee_record::print() {
        std::cout << this->name << " " << this->id << std::endl;
}

int main() {
        employee_record rec("wiki", 1);
        employee_record rec_1("stack", 2);

        rec = rec_1; // assign rec_1 to rec

        rec.print();
        return 0;
}
  • Let us save the code sample.cpp and try to compile and run.
compile: 
bosch@bosch-Inspiron-N5050:~$ g++ sample.cpp -o sample
Run:
bosch@bosch-Inspiron-N5050:~$ ./sample
stack 2
*** Error in `./samle': double free or corruption (fasttop): 0x0000000001462030 ***
Aborted (core dumped)
bosch@bosch-Inspiron-N5050:~$
  • The above program is a buggy program without proper assignment operator and copy constructor. If we run the program it will be undefined behavior.
  • The statement rec = rec_1 , will invoke default overloaded assignment operator ,and The default assignment operator in C++ recursively applies the assignment operators of the class’s members.
  • Here employee_record class containing a pointer to char array name and integer id.
  • We can consider employee_record class as a user defined data type.
  • To make the behavior  of employee_record class as a built in data type we have to provide copy constructor and overloaded assignment operator. 

So it is clearly that The compiler generated copy constructor and assignment operator may not be sufficient when we have pointers in a class. So let us modify the program as below

#include <iostream>
#include <string.h>

class employee_record {

private:
	int id;
	char* name;

public:
	employee_record(char* name_, int id_) {

		id = id_;
		size_t size = strlen(name_) + 1;
		name = new char[size];
		strncpy(name, name_, size);
	}

	virtual ~employee_record() {
		delete[] name;
	}

	employee_record(const employee_record &obj) {
		id = obj.id;
		size_t size = strlen(obj.name) + 1;
		name = new char[size];
		strncpy(name, obj.name, size);
	}

	employee_record& operator=(employee_record &obj) {
		// free old allocated memory
		delete[] name;
		name = NULL;

		id = obj.id;
		size_t size = strlen(obj.name) + 1;
		name = new char[size];
		strncpy(name, obj.name, size);
		return *this;
	}
	void print();
};

void employee_record::print() {
	std::cout << this->name << " " << this->id << std::endl;
}

int main() {
	employee_record rec("wiki", 1);
	employee_record rec_1("stack", 2);

	rec = rec_1;

	rec.print();
	return 0;
}
bosch@bosch-Inspiron-N5050:~$ g++ -g sample.cpp -o sample
sample.cpp: In function ‘int main()’:
sample.cpp:51:31: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  employee_record rec("wiki", 1);
                               ^
sample.cpp:52:34: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  employee_record rec_1("stack", 2);
                                  ^
bosch@bosch-Inspiron-N5050:~$ 
bosch@bosch-Inspiron-N5050:~$ ./sample
stack 2

Why do we need the copy and swap idiom in C++?

Let us think what we have done until now…

We have made copy constructor and overloaded assignment operator. Let us look at the code ..

    // copy constructor
	employee_record(const employee_record &obj) {
		id = obj.id;
		size_t size = strlen(obj.name) + 1;
		name = new char[size];
		strncpy(name, obj.name, size);
	}
    // assignment operator
	employee_record& operator=(employee_record &obj) {
		// free old allocated memory
		delete[] name;
		name = NULL;

		id = obj.id;
		size_t size = strlen(obj.name) + 1;
		name = new char[size];
		strncpy(name, obj.name, size);
		return *this;
	}

Observation:

  • In assignment operator and copy constructor , there is code duplication. Our assignment operator effectively duplicates all the code we’ve already written  in copy constructor.
  • In overloaded assignment operator , if memory allocation of char*name would fail , then there is invalid state of object. we have to handle exception if new fails.

Copy and swap idiom is a way of solving above two problems.

#include <iostream>
#include <string.h>

class employee_record {

private:
	int id;
	char* name;

public:
	employee_record(char* name_, int id_) {

		id = id_;
		size_t size = strlen(name_) + 1;
		name = new char[size];
		strncpy(name, name_, size);
	}

	virtual ~employee_record() {
		delete[] name;
	}
	 friend void swap(employee_record& obj1, employee_record& obj2)
	 {
		    using namespace std;
	        swap(obj1.id, obj2.id);
	        swap(obj1.name, obj2.name);
	 }
    // copy constructor
	employee_record(const employee_record &obj) {
		id = obj.id;
		size_t size = strlen(obj.name) + 1;
		name = new char[size];
		strncpy(name, obj.name, size);
	}
    // assignment operator
	employee_record& operator=(employee_record obj) {
		swap(*this,obj);
		return *this;
	}
	void print();
};

void employee_record::print() {
	std::cout << this->name << " " << this->id << std::endl;
}

int main() {
	employee_record rec("wiki", 1);
	employee_record rec_1("stack", 2);

	rec = rec_1;

	rec.print();
	return 0;
}
  • In the above example, the parameter to the ‘operator=()’ is passed by value
  • The passing parameter by value calls copy constructor to create a employee_record object local to the ‘operator=()’ function.
  • The value of the local object is swapped with ‘*this’ object.

Ref:

https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom



Related Contents to follow