我目前正在大学攻读C ++课程。我理解使用向量进行浅层和深层复制的一般概念,但是在我的教科书中有一个让我感到困惑的例子。
请假设它是一个执行不佳的向量,没有定义复制构造函数,因此它只执行数据的浅层复制。
我理解第一部分正在发生的事情
声明
vector<int> v2(v1);
向量
v1
作为const引用参数传递给向量副本 构造函数,因此无法更改v1
,因此变量v2
初始化为向量v1
的副本。每个数据字段都是 已复制,稍后对v2
所做的任何更改都不应影响v1
。什么时候 复制v1.the_data
中的值,v1.the_data
和v2.the_data
v1.the_data
将指向同一个数组因为
v2.the_data
和v1[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_data
和v2
指向内存中的相同位置,因此他们“共享”相同的向量,以便当20添加到它的两端时向量应该获得一个额外的整数。
非常感谢有助于理解为什么v1
修改后{{1}}的商品数量不会发生变化。
答案 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;给出浅拷贝,因为只复制了一个指针。这给出了几个问题:在一个向量中调整实际数据会导致另一个向量中的状态不一致,并且不能再进行内存管理。