C ++浅层和深层复制 - 反映向量的num_items中的变化

时间:2014-06-17 13:27:58

标签: c++ vector copy deep-copy shallow-copy

我目前正在大学攻读C ++课程。我理解使用向量进行浅层和深层复制的一般概念,但是在我的教科书中有一个让我感到困惑的例子。

请假设它是一个执行不佳的向量,没有定义复制构造函数,因此它只执行数据的浅层复制。

我理解第一部分正在发生的事情

  

声明

     
    

vector<int> v2(v1);

  
     

向量v1作为const引用参数传递给向量副本   构造函数,因此无法更改v1,因此变量v2   初始化为向量v1的副本。每个数据字段都是   已复制,稍后对v2所做的任何更改都不应影响v1。什么时候   复制v1.the_data中的值,v1.the_datav2.the_data   v1.the_data将指向同一个数组

     

因为v2.the_datav1[2] = 10; 指向同一个对象,所以   声明

v2[2]
     

也会更改v2。因此,v1被视为浅层副本   v2.num_items

但是我很难理解这一部分。我不太清楚为什么v1.push_back(20); 也不会在浅拷贝中改变。

  

声明

20
     

会将v1[5]插入v1.num_items并将v2.num_items更改为6,但会   不要更改v1.the_data

我目前的想法是v2.the_datav2指向内存中的相同位置,因此他们“共享”相同的向量,以便当20添加到它的两端时向量应该获得一个额外的整数。

非常感谢有助于理解为什么v1修改后{{1}}的商品数量不会发生变化。

4 个答案:

答案 0 :(得分:2)

您的教科书是否在标准库中讨论std::vector?如果是这样,那就错了。来自vector<int> v2(v1);的{​​{1}} 复制构造 v2。这是一个深层副本,两个容器不共享存储空间,完全是分开的。

相反,如果这是一个执行不当的v1类,并且容器共享存储,那么在一个中更改现有元素将反映在另一个中。类似于vector的操作改变了一个容器的push_back而不是其他容器会导致他们对其大小不一致。

答案 1 :(得分:2)

假设我们正在讨论标准std::vector

在此声明中复制向量时:

vector<int> v2(v1);

v2是通过复制v1的每个元素构建的。 v1和v2不共享任何内存。

这部分:

  

v1.the_data和v2.the_data都将指向同一个数组

     

因为v1.the_data和v2.the_data指向同一个对象,

错了。

您可以通过将每个向量的基础数组地址与data() member function进行比较来说服自己。

编辑:

假设你疯狂到不使用std::vector并使用一个在复制时“共享”其后端数组的实现(我不会谈论这个设计的问题:谁拥有数组?谁{{ 1}}它?)

您的老师提出的问题是,当delete[]被修改时(例如添加了一个元素),v1不知道它,并且大小不变。

阵列的每个其他所有者都应该观察对一个向量做出的任何v2(或类似),以正确反映数组的大小。

要么:

1)你实现了某种观察者模式,让每个向量都知道任何修改(并且它比听起来更困难)

2)你使用技巧来存储后端数组本身的长度。

当通过其中一个向量引用修改“共享”数组时,你会遇到类似的问题来使每个迭代器无效......这是一场噩梦! STL容器 all 设计用于管理自己的内存有很好的理由,因此总是提供深层复制语义。

答案 2 :(得分:2)

该声明似乎假设了一个特定的实现 vector(不符合std::vector)。假设, 例如,我们有一个非常天真的实现:

template <typename T>
class Vector
{
    T* myData;
    int mySize;
    int myCapacity;
public:
    void push_back( T const& newValue )
    {
        if ( mySize == myCapacity ) {
            //  Extend the capacity...
        }
        myData[mySize] = newValue;
        ++ mySize;
    }
    T& operator[]( int index )
    {
        return myData[index];
    }
};

如果您没有复制构造函数,则在复制向量时, 所有三个变量都会相同:两个向量都会有 指向相同数据,相同大小和相同容量的指针。 但这些是副本:当您使用[]时,您会修改内存 由myData指出,两个向量都是相同的;什么时候 您在push_back上执行v1,更新v1尺寸, 在其大小的本地副本。

当然,这种实现在很多方面都是天真的。 像std::vector这样的好的实现需要 相当多的想法,不仅仅是因为如果需要深层复制 语义,但也出于异常安全的原因( T的构造函数可能会抛出),并避免强加 不必要的要求(特别是默认构造函数)。

另外,如果我试图使用一个实现不好的矢量作为浅拷贝的例子,我不会称之为vector,因为那会立即让人想起std::vector的图像,实施得不好(并不在我所知道的库实现中)。

答案 3 :(得分:0)

理解这个问题中的陈述的问题在于我们是否必须将vector视为std :: vector或理论实现。 std :: vector不允许浅层复制,原因在语句中给出:不变量因此而不受尊重。

现在用&#34; the_data&#34;进行理论实施。和&#34; num_items&#34;成员。在这里复制矢量应该给出一个深层复制,但只是复制&#34; the_data&#34;给出浅拷贝,因为只复制了一个指针。这给出了几个问题:在一个向量中调整实际数据会导致另一个向量中的状态不一致,并且不能再进行内存管理。