[英]When does C++ perform deep copying and shallow copying?
我想知道C ++何時進行深度復制,何時進行深度復制。
例如:
int find()
{
int n=5;
return n;
}
為了在移出函數后刪除n,它必須創建一個臨時變量n,並將其返回給調用方。 結果,那是淺表副本,對嗎?
結果,那是淺表副本,對嗎?
淺表副本始終引用原始對象†所引用的內容。 深層副本是指所引用資源的副本†† (該資源的新副本必須由副本構造函數創建)。 僅當復制的對象†是引用對象(即它引用某種資源)時,這種區別才有意義。
int
類型不引用任何對象,因此就類型系統而言,它不是引用的。 但是在類型系統之外,可以給它提供參考意義。 例如,用整數表示資源(例如存儲在數據庫中的實體)的身份是非常典型的。 您需要考慮整數是否是這種情況。 在面向對象的設計中,此類標識符通常包裝在†††類中(可以指定為支持深層副本)。
非類類型的副本總是淺的。 只有復制構造函數††††可以執行深層復制。 如果5標識某個資源,則5的副本也引用該相同資源。
與深層復制和淺層復制相關的引用類型的示例:引用,指針,具有引用成員的類。 usch類的示例:智能指針,引用標識符的包裝††† 。 在這些指針和引用中,它們不是類,因此會被淺表復制。 根據復制構造函數的實現,類實例的復制可能淺或深。
然后是搬家建築。 移動構造是一個淺表副本,它以強制任何平凡的淺表副本會違反的類不變式的方式修改原始對象。 例如,唯一指針的move構造函數將淺表復制內部指針,並將原始指針設置為null,以便保持指針所有權的唯一性。
†我說的是對象是為了簡單起見,但這也適用於引用類型的副本-也不是對象。
††資源可能是內存中的另一個對象,例如文件描述符或執行線程。
†††示例: std::thread
,它包裝操作系統提供的較低級別的標識符。
††††任何函數都可以執行深層復制,但復制構造函數是唯一由復制初始化調用的函數。
int
不是引用類型,因此沒有淺拷貝或深拷貝的問題。 它只是一個副本。
我們可以理解深度復制和淺層復制,如下所示:
深拷貝
深層副本將復制所有字段,並復制這些字段所指向的動態分配的內存。 當將對象及其引用的對象一起復制時,將發生深層復制。
淺拷貝
淺拷貝是對象的按位拷貝。 創建一個新對象,該對象具有原始對象中值的精確副本。 如果對象的任何字段是對其他對象的引用,則僅復制參考地址,即僅復制內存地址,而不復制實際對象。
術語“淺拷貝”和“深拷貝”通常被理解為涉及自身間接封裝某些對象的類型。
因此,例如,一個帶有指針的類(我們假設它指向某物):
struct Foo
{
Bar* ptr;
};
復制Foo
,它是否也指向復制的Bar
( 深層 )? 還是新的Foo
僅僅共享指向原始Bar
( 淺 )的原始指針?
這將取決於復制的執行方式-通常,您的Foo
將具有一個復制構造函數,而正是這個復制構造函數中的代碼才有區別。
例如,所有標准C ++容器(例如vector
)在內部都是由指向一些已分配緩沖區的指針組成的,但是它們具有復制構造函數,可確保在復制矢量時復制整個緩沖區,以便每個矢量都有其自己的 ,獨立緩沖區。 這是一個深復制。
但是我上面給出的示例,沒有任何復制構造函數或其他可愛的代碼,在分配時將僅執行淺表復制,因為除了復制ptr
的值外,我沒有告訴它做任何事情。
至於您的情況: int
只是一個值,因此我們無法進行這種比較。 您只有簡單而簡單的值副本。 實現該功能需要多少個臨時人員的內部細節是無關緊要的(無關緊要); 在這種情況下,談論淺副本與深副本是沒有意義的,因為從字面上看,沒有封裝的,間接擁有的對象擁有或不擁有的對象,可以被視為淺或深的副本或任何復制的對象。 我們通常可以對任何非類類型說這句話。
您對代碼行為的描述與您提供的源代碼一致,但是編譯器可能不會這樣做。
允許C ++編譯器實現一個按條件規則:即,您的源代碼指定的是您的意圖,而不是最終可執行文件的形式。
換句話說,編譯器可以將整個函數調用替換為5
。
簡而言之, 深層副本會在源對象中與該對象相關的每個字節中創建一個副本。 小於此的任何副本都是淺副本。 除非以某種方式重載=
,否則=
將獲取淺表副本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.