×

Search anything:

copy and swap idiom in C++

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article, we have explained copy and swap idiom in C++.

Table of contents

  1. What is the copy-and-swap idiom?
  2. A way of implementation

1. What is the copy-and-swap idiom?

The simple answer that can explain this idiom is by saying is a way of implementing the assignment operator in terms of a swap function.

And it all started with the copying of pointer members of a class.

Let's look at the next class definition

#include <iostream>

using namespace std;

class A
    {
        public:
            int pSize;

            int *p;

            A(int pSize)
                {
                this->pSize = pSize;
                p = new int[pSize];
                cout <<"obj created \n";
                };
            ~A()
                {
                pSize = 0;
                delete []p;
                };

    };

int main()
{
    A *a1 = new A(3);
    A *a2;

    a1->p[0]=1;

    cout<<a1->p[0] <<"\n";

    a2 = a1;

    cout<<a2->p[0] <<"\n";

    return 0;
}

Output:

obj created 
1
1

Notice that the message from the object constructor is called only once.
The object a2 was copied by reference invoking the same allocated memory for a1.

We might then try to add the copy constructor.

#include <iostream>              

using namespace std;                   

class A                                                                      
    {
        public:
            int pSize;

            int *p;

            A(int pSize)
                {
                this->pSize = pSize;
                p = new int[pSize];
                cout <<"obj created \n";
                };

            A(const A &a)
            {
                pSize = a.pSize;
                p = new int [pSize];
                for (int i=0;i<pSize;i++)
                    p[i] = a.p[i];
                cout <<"obj copied \n";
            }
            ~A()
                {
                pSize = 0;
                delete []p;
                };

    };

int main()
{
    A *a1 = new A(3);

    a1->p[0] = 1;

    cout<<a1->p[0] <<"\n";

    A a2(*a1);

    cout<<a2.p[0] <<"\n";

    a1->p[0] = 2;

    cout<<a2.p[0] <<"\n";

    return 0;
}

Output:

obj created 
1
obj copied 
1
1 

The biggest mistake here is to copy the pointer itself instead of copying the value of it, meaning instead of using the for statement for each i element p[i] = a.p[i]; you might have p = a.p; with the

Output:

obj created 
1
obj copied 
1
2

so, at the copying constructor we need to copy all the elements of the pointer member and not the pointer reference.

We might use the copy function instead of the for statement but we need to include the algorithm library:

copy(a.p, a.p + pSize, p);

Things are getting complicated when we want to implement the assignment operator.
To doing so, we start from the definition of copy constractor the only thing we change is the function name by adding operator = with no returns. Notice that the domain of the two remains the same: const A &a

#include <iostream>
#include <algorithm>

using namespace std;

class A
    {
        public:
            int pSize;

            int *p;

            A(int pSize)
                {
                this->pSize = pSize;
                p = new int[pSize];
                cout <<"obj created \n";
                };

            A(const A &a)
            {
                pSize = a.pSize;
                p = new int [pSize];
                copy(a.p, a.p + pSize, p);
                cout <<"obj copied \n";
            }
            void operator = (const A &a)
            {
                pSize = a.pSize;
                p = new int [pSize];
                copy(a.p, a.p + pSize, p);
                cout <<"obj assigned \n";
            }
            ~A()
                {
                pSize = 0;
                delete []p;
                };

    };

int main()
{
    A *a1 = new A(3);

    a1->p[0] = 1;

    cout<<a1->p[0] <<"\n";

    A a2(*a1);

    cout<<a2.p[0] <<"\n";

    a1->p[0] = 2;

    cout<<a2.p[0] <<"\n";

    a2 = *a1;

    cout<<a2.p[0] <<"\n";

    return 0;
}

Output:

obj created 
1
obj copied 
1
1
obj assigned 
2

If we remove the & reference from the domain of the assignment operator, then the copy constructor will be called prior assignment.

void operator = (const A a)

Output:

obj created 
1
obj copied 
1
1
obj copied 
obj assigned 
2

Why is that ? Because, when the assignment operator is called it creates a local copy of the a object and after that makes the assignment.

Some questions needs to be raised here:

  1. What happens if we make a self assignment?
    In this case we might add a check condition:
if (this != &a) {...}
  1. What happens if the new memory allocation fails to allocate ?
    In this case we might add another check condition:
p = pSize ? new int [pSize] : NULL;
  1. Code duplication

The code from the assignment operator looks exactly the same from the one of the copy constructor.

So, how can we avoid all these ?

2. A way of implementation

The core way is to use the swap function by invoking it in the operator definition for each member of the class. This is a little bit hard, since we might have objects with many, and many, and many members, but still easier than using the for statement.

void operator = (A &a)
{
    swap(this->pSize, a.pSize);
    swap(this->p, a.p);

    cout <<"obj assigned \n";
}

Notice that we have removed the const from the domain since there is no implementation of swap for it, but we have used previously to avoid changing values during copying.

With this article at OpenGenus, you must have the complete idea of copy and swap idiom in C++.

copy and swap idiom in C++
Share this