74

I wonder whether copying a vector I am copying the vector with its values (whereas this is not working with array, and deep copy need a loop or memcpy).

Could you hint to an explanation?

Regards

kiriloff
  • 25,609
  • 37
  • 148
  • 229
  • Don't use `memcpy` for `vector`. The object contained in vector may not be POD, they may be classes having virtual functions. Use `std::copy` or simple `vector` to `vector` assignment. – Ajay Jul 05 '12 at 16:57
  • 2
    The 'deep' vs. 'shallow' distinction doesn't make much sense in a language that defaults to value semantics and doesn't try to hide the fact that it uses pointers (so that pointers are objects with their own values, distinct from the object they reference). Copies will always be by-value, and whether that constitutes 'deep' copying vs. 'shallow' copying depends on your definition. – bames53 Jul 05 '12 at 18:00

2 Answers2

134

You are making a deep copy any time you copy a vector. But if your vector is a vector of pointers you are getting the copy of pointers, not the values are pointed to

For example:

std::vector<Foo> f;
std::vector<Foo> cp = f; //deep copy. All Foo copied

std::vector<Foo*> f;
std::vector<Foo*> cp = f; //deep copy (of pointers), or shallow copy (of objects).
//All pointers to Foo are copied, but not Foo themselves
Element
  • 3,981
  • 7
  • 42
  • 51
Andrew
  • 24,218
  • 13
  • 61
  • 90
  • 4
    +1 I would consider the second example as shallow copy. `int *a, *b; a=b; // Shallow copy`. In case of vectors too, aren't we doing something like this ? BTW, its de*e*p and not deap :) – Mahesh Jul 05 '12 at 16:16
  • 3
    Sometimes I find these terminologies confusing when I see them being used differently, in different posts. One could just say, in case of pointers, they're shallow-copy; both seem to be correct, depending on how you interpret them. – Nawaz Jul 05 '12 at 16:16
  • 6
    The confusion probably comes from a missing distinction between "pointers" and "pointees". Pointers are just ordinary objects, and they are indeed copied exactly the way one would expect. It's the *pointees* that people are confused about. – Kerrek SB Jul 05 '12 at 17:13
  • Doesn't it depend on the implementation of `Foo`'s copy constructor, or copy assignment? Isn't it one of those ultimately called? (and in that case, which?) – Gauthier Nov 09 '16 at 09:07
  • Doesn't `std::unique_ptr` still have to be deep-copied? – Pr0methean Apr 22 '19 at 17:24
  • 2
    @user833771 The questions was not about `unique_ptr`. For `unique_ptr`, it can't be copied, you can either `move` it or create a new one deep-copying the content. – Andrew Apr 22 '19 at 19:29
5

Vector will resize to have enough space for the objects. It will then iterate through the objects and call the default copy operator for every object.

In this way, the copy of the vector is 'deep'. The copy of each object in the vector is whatever is defined for the default copy operator.

In examples... this is BAD code:

#include <iostream>
#include <vector>

using namespace std;

class my_array{
public:
    int *array;
    int size;
    my_array(int size, int init_val):size(size){
        array = new int[size];
        for(int i=0; i<size; ++i)
            array[i]=init_val;
    }
    ~my_array(){
        cout<<"Destructed "<<array[0]<<endl;
        if(array != NULL)
            delete []array;
        array = NULL;
        size = 0;
    }

};

void add_to(vector<my_array> &container){
    container.push_back(my_array(4,1));
}

int main(){

    vector<my_array> c;
    {
        my_array a(5,0);
        c.push_back(a);
    }
    add_to(c);
    //At this point the destructor of c[0] and c[1] has been called.
    //However vector still holds their 'remains'
    cout<<c[0].size<<endl; //should be fine, as it copies over with the = operator
    cout<<c[0].array[0]<<endl;//undefined behavior, the pointer will get copied, but the data is not valid
    return 0;
}

This is BETTER code:

#include <iostream>
#include <vector>

using namespace std;

class my_array{
public:
    int *array;
    int size;
    my_array(int size, int init_val):size(size){
        cout<<"contsructed "<<init_val<<endl;
        array = new int[size];
        for(int i=0; i<size; ++i)
            array[i]=init_val;
    }
    my_array(const my_array &to_copy){
        cout<<"deep copied "<<to_copy.array[0]<<endl;
        array = new int[to_copy.size];
        size = to_copy.size;
        for(int i=0; i<to_copy.size; i++)
            array[i]=to_copy.array[i];
    }

    ~my_array(){
        cout<<"Destructed "<<array[0]<<endl;
        if(array != NULL)
            delete []array;
        array = NULL;
        size = 0;
    }

};

void add_to(vector<my_array> &container){
    container.push_back(my_array(4,1));
}

int main(){

    vector<my_array> c;
    {
        my_array a(5,0);
        c.push_back(a);
    }
    add_to(c);
    //At this point the destructor of c[0] and c[1] has been called.
    //However vector holds a deep copy'
    cout<<c[0].size<<endl; //This is FINE
    cout<<c[0].array[0]<<endl;//This is FINE
    return 0;
}
Christian Sarofeen
  • 2,202
  • 11
  • 18