c ++向量构造函数和赋值问题

时间:2013-07-22 17:31:09

标签: c++

我对以下陈述的第2行和第3行中发生的事情感到困惑。据我所知

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

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

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

3 个答案:

答案 0 :(得分: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复制为 它知道的深处,哪些是包含的元素。然后, 更深层次的是所包含的要素的责任 (或不)。默认的复制构造函数将执行成员 成员副本(如果所有包含的元素都有副本 建设者,你是安全的,但如果有,例如原始指针, 您可能必须自己编写,为对象提供副本 你想要的语义。

答案 1 :(得分:3)

(1)将导致默认的构造向量(如您所知)。

(2)和(3)将分别产生来自vec1vec2的复制构造的载体。

矢量复制构造函数将构造源矢量的每个元素复制到新矢量中。您可以从此副本实现中获得一个免费的浅表副本。对于您的特定对象AB浅层和深层副本完全相同,因此您最终也可以使用深层副本。

答案 2 :(得分:0)

我认为它是浅薄的和深刻的复制概念。根据我的说法,它不会调用Default C'tor,即它会在两种情况下直接调用Default Copy C'tor,而By Default实现是一个浅层复制,因为它不会处理数据成员的内存分配(如果有的话)。 / p>