2

我对以下语句的第 2 行和第 3 行发生的事情感到困惑。据我了解

line2 ( vector<A> vec2(vec1); ) :对于存储在 vec1 中的每个 A 实例,将调用复制构造函数并将其存储在 vec2 中。让我感到困惑的是,即使我没有指定自定义复制构造函数,默认复制构造函数创建 A 的实例,可能调用 A 和 B 的默认构造函数,但 THEN 实际上正确地将 A 的成员数组的原始值初始化为拷贝和 A 的成员变量 b 的向量的值到拷贝的 B 的向量。那是免费的深度复制。这个对吗?

line3 ( vector<A> vec3 = vec2;) :默认构造函数将创建 A 的实例,然后调用存储实例的赋值运算符来初始化它,而不是调用复制构造函数。在这里,我再次获得免费的深度复制。

1. vector<A> vec1;
2. vector<A> vec2(vec1);
3. vector<A> vec3 = vec2;

其中 A 的定义如下所示。

class B
{
public:
    vector<int> db;
};

class A
{
public:
    char data[5];
    int x;
    B bee;
};

这是证明深度复制正在发生的主要方法

int main()
{
    A a, b;
    a.data = {'a','b','c','d','\0'};
    a.x = 1;
    a.bee.db.push_back(99);
    a.bee.db.push_back(100);


    b.data = {'z','x','y','w','\0'};
    b.x = 2;
    b.bee.db.push_back(1);
    b.bee.db.push_back(2);

    vector<A> vec;
    vec.push_back(a);
    vec.push_back(b);

    map<int, std::vector<A>> map1;
    vector<A> vec1(vec);

    map1[1] = vec1;

    std::vector<A> vec2 = map1[1];

    cout << vec2[0].data<< endl;
    cout << vec2[0].bee.db[0] << endl;

    vec2[0].x = 77777;
    vec2[0].data = {'c','o','p','y','\0'};

    cout << "vec1[0].x: " << vec1[0].x << endl;
    cout << "vec1[0].data: " << vec1[0].data << endl;
    return 0;
}
4

3 回答 3

4

首先,所有的拷贝和赋值std::vector都是深拷贝,至少在 C++11 之前。(在 C++11 中,也有涉及移动语义的版本。)

二、您的评价:

`std::vector<A> vec3 = vec2;

是不正确的。因为 的类型与vec2正在初始化的变量的类型相同,所以这与您的情况 2 完全相同。(如果类型不同,正式地,将调用转换构造函数将右侧转换为正确的类型,并且然后将使用复制构造函数。但允许编译器优化副本。)

另外:如果你写过:

std::vector<A> vec3;
vec3 = vec2;

编译器将默认构造一个空的vec3,然后分配它。但是赋值仍然会调用每个A 对象的复制构造函数(而不是赋值运算符),因为在你进行赋值时没有任何构造的A对象 vec3(并且赋值只能是完全构造的对象)。

最后:关于深拷贝:std::vector尽可能深的拷贝,即包含的元素。之后,包含的元素有责任深入(或不深入)。默认的复制构造函数将逐个成员进行复制(因此,如果所有包含的元素都有复制构造函数,那么您是安全的),但是如果有原始指针,您可能必须编写自己的,给对象复制你想要的语义。

于 2013-07-22T17:52:11.523 回答
3

(1) 将产生一个默认的构造向量(如您所知)。

(2) 和 (3) 都将分别从vec1和生成复制构造的向量vec2

向量复制构造函数会将源向量的每个元素复制到新向量中。您可以从此复制实现中获得一个免费的浅拷贝。对于你的特定对象来说AB浅拷贝和深拷贝是完全一样的,所以你实际上也得到了一个深拷贝。

于 2013-07-22T17:42:03.460 回答
0

我认为这是浅而深的复制概念。根据我的说法,它不会调用 Default C'tor,即在这两种情况下它将直接调用 Default Copy C'tor,并且默认实现是浅拷贝,因为它不会处理数据成员的内存分配(如果有的话)。

于 2013-07-22T17:36:37.183 回答