Different ways to copy a vector in C++

C++ STL | Copying a vector: Learn - different ways to copy a vector in C++ STL, Shallow copy vs Deep copy, Different copy methods, etc.
Submitted by Radib Kar, on July 07, 2020

In this article, we are going to see how to copy a vector into another vector in various ways? We will also learn about shallow copy and deep copy, their differences, and consequences while checking each of the vector copy methods.

Before starting with the methods for copying a vector into the other, let's discuss what shallow copy and deep copy are. What are differences b/w them, and why do we need two different terms to classify the copy process.

Shallow copy vs Deep copy

A vector is essentially an object which has some memory allocation upon execution. Now say you have defined and declared some vector A and you want to copy the content of A into another vector B. Now, there can be two cases, one case is we define a new vector B, but doesn't allocate any new memory for that, rather just link up to the vector A similar like vector B is pointing to the same location of vector A. Thus it has the same copy of vector A. This is known as a shallow copy. If we make any changes to vector A even after our copy operation is done, vector B will have the same changes which are not intended.

On the other hand, when we create a new location for vector B and copy contents from vector A, then it's known as deep copy. If we make any change to vector A after the copy operation it won't be reflected in vector B which is of course intended.

While discussing the copy method we will detail whether it's a shallow copy or deep copy and why so that you never make any mistake using the copy method and guess it's a deep copy! (yes we often intend to have a deep copy normally).

Different copy methods

1) Copy content iteratively

Here we simply copy the contents of vector A into vector B iteratively. Vector B is defined as a new location, so it's of course a deep copy. We have verified that too by changing elements after our copy operation.

Example code:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined
    vector<int> B;

    //copy content iteratively
    for (int i = 0; i < A.size(); i++) {
        B.push_back(A[i]);
    }
    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A
    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

2) Copy content recursively

Here we simply copy the contents of vector A into vector B recursively. Vector B is defined as a new location, so it's of course a deep copy. We have verified that too by changing elements after our copy operation.

Example code:

#include <bits/stdc++.h>
using namespace std;

//to copy recursively
//check reference is passed for vector B
void myrecur(int i, vector<int> A, vector<int>& B)
{
    //base case
    if (i == A.size())
        return;

    //copy content
    B.push_back(A[i]);
    myrecur(i + 1, A, B);
}

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined
    vector<int> B;

    //copy content iteratively
    myrecur(0, A, B);
    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A
    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

3) Using assignment operator "=" (overwriting the current contents)

Another way to copy a vector into another is by using the assignment operator. Yes, it works perfectly! Don't try this at all for static array!. The reason behind why such assignment operator works because it simply overwrites the current members if any available, else assigns the value from where it's being copied. Below is an example and we can see, it's a deep copy.

Note: In Java, assignment operator does a shallow copy only.

Example code:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined and copy A 
    //with assignment operator
    vector<int> B = A;

    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A
    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

4) Using copy constructor

We can also pass the vector A as a constructor to vector B which will invoke copy constructor and serve a deep copy.

Example code:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined and vector  
    //A passed in the constructor
    //this is also considered as an 
    //initialization method too
    vector<int> B(A);

    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A

    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

5) std::copy() function

There is another method using the std function copy(). Though it's less used you should know a variety of functions the C++ standard library has. And yes, it does a deep copy.
The copy function takes three argument

The first one is: iterator from where copy will be started: beginning of vector A

The second one is: iterator to where copy will be ended: the end of vector A

The third one is: output iterator which points to destination vector: beginning of Vector B

So the syntax is,

void copy(argumnet1, argument2, argument3)

Example code:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined
    vector<int> B(5);

    //copy using std::copy

    copy(A.begin(), A.end(), B.begin());

    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A

    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

A very important note about the above code:

Check here I have defined vector B as vector<int> B(5), but if you look in earlier codes you will find I had defined like vector<int> B

Now the question is why I made the change this time. Is there any reason or I just did that! Okay, let's say we do the same as before.

Then the code will be:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined
    vector<int> B;

    //copy using std::copy

    copy(A.begin(), A.end(), B.begin());

    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A
    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Segmentation fault (core dumped)

Oops! The output is segmentation fault!. Why? Probably now you get the point. Whenever we write vector<int> B the vector has no idea about how many elements will be there and it doesn't allocate memory for elements at all. But in our copy function there is the output iterator which tries to traverse vector B, but fails as no memory allocated for elements. That's why segmentation fault and we need to allocate memory, rather say define the vector along with its elements. That's why we need vector<int> B(5). Go through my article on vector initialization methods to know in details about this. Oops, one little mistake can lead you to segmentation fault and you may just get insane to find the bug! Nice lesson I hope.

6) vector::assign() function

Vector has an inbuilt function too to copy contents from other content. It's named assign() function. It's again a deep copy method.

The syntax is like below,

destination_vector.assign (
    iterator to the beginning of source_vector, 
    an iterator to the end of source_vector
    );

Example code:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    //vector A;
    //a vector of 5 element where each 
    //element is -1
    vector<int> A(5, -1); 

    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;

    //vector B defined
    vector<int> B;

    //copy using vector::assign
    B.assign(A.begin(), A.end());

    cout << "Vector A copied into vector B\n";
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    //to check deep copy or shallow copy
    //changing one element in vector A
    A[4] = 4;

    cout << "After making the change...\n";

    //printing vector A
    cout << "printing vector A:\n";
    for (auto it : A)
        cout << it << " ";
    cout << endl;
    
    //printing vector B
    cout << "printing vector B:\n";
    for (auto it : B)
        cout << it << " ";
    cout << endl;

    cout << "No change in B, it's deep copy!\n";

    return 0;
}

Output:

printing vector A:
-1 -1 -1 -1 -1
Vector A copied into vector B
printing vector B:
-1 -1 -1 -1 -1
After making the change...
printing vector A:
-1 -1 -1 -1 4
printing vector B:
-1 -1 -1 -1 -1
No change in B, it's deep copy!

Okay, that's all. So, we found all the copy methods actually do a good job as they all do deep copy and we can use any one of them blindly. Do comment and let us know which copy method you would prefer and why?


Related Tutorials




Comments and Discussions!

Load comments ↻






Copyright © 2024 www.includehelp.com. All rights reserved.