C++中的std vector——深拷贝还是浅拷贝

74

我想知道复制一个向量是否会将其值一并复制(而这在数组中不起作用,深度复制需要循环或memcpy)。

你能否给出一个解释的提示?

致敬


不要在vector中使用memcpyvector中包含的对象可能不是POD类型,它们可能是具有虚函数的类。请使用std::copy或简单的vector<T>vector<T>赋值。 - Ajay
2
“深拷贝”和“浅拷贝”的区分在一种默认使用值语义并且不试图隐藏其使用指针的事实(因此指针是具有自己值的对象,与它们所引用的对象不同)的语言中没有太多意义。复制将始终按值进行,而这是否构成“深拷贝”与“浅拷贝”取决于您的定义。 - bames53
2个回答

135
你每次复制向量时都在进行深度复制。但是如果你的向量是指针向量,你获得的是指针的副本,而不是指向的值。
例如:
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

4
+1 我认为第二个例子是浅拷贝。int *a, *b; a=b; // 浅拷贝。对于向量来说,我们也不是在做类似的事情吗?顺便说一下,它是 deep 而不是 deap :) - Mahesh
3
有时候我看到这些术语在不同的帖子中被使用时,会感到混淆。例如,在指针的情况下,有些人称其为浅拷贝,而另一些人则将其称为浅复制。这两种说法都是正确的,具体取决于你如何解释它们。 - Nawaz
6
混淆可能源于缺少对“指针”和“指向对象”的区分。指针只是普通的对象,它们确实会被复制,就像人们所期望的那样。人们所困惑的是指向对象 - Kerrek SB
这不取决于 Foo 的复制构造函数或复制赋值函数的实现吗?它们中的一个最终被调用了吧?(如果是这种情况,是哪个?) - Gauthier
std::unique_ptr 还需要进行深拷贝吗? - Pr0methean
2
@user833771 这个问题不是关于 unique_ptr 的。对于 unique_ptr,它不能被复制,你只能将其 move 或者创建一个新的并深度复制其内容。 - Andrew

6

向量将调整大小以获得足够的空间,然后迭代遍历对象,并为每个对象调用默认的复制运算符。

这样,向量的复制是“深度”的。向量中每个对象的副本都是默认复制运算符定义的内容。

在示例中... 这是糟糕的代码:

#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;
}

这是更好的代码:
#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;
}

更好的做法是五个规则。 :) (你使用了旧的三个规则) - Arafangion
他实际上实现了“两个规则” :) - Sriram Murali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接