簡體   English   中英

C ++淺層和深層復制-反映向量num_items中的變化

[英]C++ Shallow and deep copying - reflecting changes in the num_items of a vector

我目前正在大學攻讀C ++課程。 我了解使用向量進行淺層和深層復制的一般概念,但是我的教科書中有一個例子讓我感到困惑。

請假定它是一個實現較差的向量,未定義任何復制構造函數,因此它僅執行數據的淺表復制。

我了解第一部分的情況

在聲明中

vector<int> v2(v1);

將向量v1作為const引用參數傳遞給向量副本構造函數,因此無法更改v1 ,然后將變量v2初始化為向量v1的副本。 每個數據字段都將被復制,以后對v2所做的任何更改都不會影響v1 復制v1.the_data的值時, v1.the_datav2.the_data都將指向同一數組

因為v1.the_datav2.the_data指向同一對象,所以該語句

 v1[2] = 10; 

也更改v2[2] 因此,將v2視為v1的淺表副本。

但是,我很難理解這一部分。 我不太確定為什么v2.num_items也不會在淺表副本中更改。

該聲明

 v1.push_back(20); 

會將20插入v1[5]並將v1.num_items更改為6,但不會更改v2.num_items

我目前的想法是v1.the_datav2.the_data指向內存中的同一位置,因此它們“共享”相同的向量,因此當在其末尾添加20時,兩個向量都應獲得一個附加的整數。

在理解為什么修改v1后為什么v2的項目數不會改變的過程中,我將不勝感激。

您的教科書是否在談論標准庫中的std::vector 如果是這樣,那是錯誤的。 vector<int> v2(v1); v1 復制構造 v2 這是一個深層副本,兩個容器不共享存儲,並且是完全分開的。

相反,如果這是一個不好實現的vector類,並且容器共享存儲,則更改一個中的現有元素將反映在另一個中。 push_back這樣的操作更改了一個容器的num_items但未更改另一個容器的num_items ,將導致它們在大小上存在分歧。

假設我們正在談論標准的std::vector

當您在此語句中復制向量時:

vector<int> v2(v1);

通過復制v1的每個元素來構建v2。 v1和v2不共享任何內存。

這部分 :

v1.the_data和v2.the_data都將指向同一數組

由於v1.the_data和v2.the_data指向同一對象,

是錯的。

您可以通過將每個向量的基礎數組地址與data() 成員函數進行比較來說服自己。

編輯:

假設您已經瘋狂到不使用std::vector並使用在復制時會“共享”其后端數組的實現(我不會談論這種設計的問題:誰擁有數組?誰delete[]它?)

您的老師提出的問題是,修改v1 (例如添加了元素)后, v2對此一無所知,並且大小沒有變化。

數組的所有其他所有者都應觀察對一個矢量進行的任何push_back (或類似操作),以正確反映數組的大小。

要么:

1)您實現某種觀察者模式,以使每個向量都知道任何修改(而且難度要比聽起來的難)

2)使用技巧將長度存儲在后端數組本身中。

通過矢量引用之一修改“共享”數組時,您將遇到類似的問題,使每個迭代器均無效...噩夢! 有充分的理由說明為什么STL容器全部設計為管理自己的內存,因此總是提供深層復制語義。

該語句似乎假定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_backv1 ,更新的大小 v1 ,在其本地大小的副本。

當然,這種實現在許多方面都是幼稚的。 良好的std::vector需要大量的考慮,這不僅是因為是否需要深層復制語義,還因為出於異常安全的考慮( T的構造函數可能拋出),並且避免施加不必要的要求(在特別是默認構造函數)。

另外,如果我嘗試使用實施效果不佳的vector作為淺拷貝的示例,則不會將其稱為vector ,因為那樣會立即產生出std::vector的圖像,這不應被實施不佳(並且不在我知道的庫實現中)。

在理解此問題中的陳述時,問題在於何時必須將vector視為std :: vector或作為理論實現。 std :: vector不允許淺表復制,其原因已在語句中給出:因此,不能尊重不變式。

現在,使用“ the_data”和“ num_items”成員的理論實現。 在這里,復制向量應提供深層副本,但僅復制“ the_data”將產生淺層副本,因為僅復制了指針。 這帶來了幾個問題:在一個向量中調整實際數據將導致另一個向量狀態不一致,並且無法再進行內存管理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM