2017-02-08 115 views
0

我很好奇你會在什麼情況下創建一個對象的淺拷貝,而不是簡單地將對象的引用傳遞給對象,或者在C++中創建對象的深層副本?在C++中使用淺拷貝而不是參考的原因?

我的理解是,如果你有一個只讀或不可變的對象,你只需要使用一個引用。如果您需要在不更改原始內容的情況下對副本進行更改,或者將某些數據編組到不同的內存地址空間,則可以進行深度複製。

我可以看到在寫入副本中使用淺拷貝(在寫入對象並完成深層副本之前),但是您是否還有其他原因希望使用淺拷貝?

編輯:試圖澄清問題。

+0

在你的例子中,我說的是傳遞一個T&around,引用(或可能是一個指針)到根對象。 – vijay267

回答

2

這裏上表中的兩個選項(假定C++ 11)爲:

  1. 具有淺拷貝構造/賦值操作符的對象。

  2. 一個對象,要麼是昂貴的複製或根本不可複製。給定C++ 11,它會有一個淺層移動構造函數/賦值運算符。

C++最終是一種面向價值的語言。直到C++ 17,像這樣簡單:

T t = someFuncReturningT(); 

至少理論上會引起復制/移動操作。 C++ 17的保證elision確保不會發生這種情況,但在此之前,這被認爲是執行復制/移動到T。當然,幾乎每個編譯器都會忽略它。但它在理論上仍然存在。

但是,對於移動操作,沒有淺拷貝並不是件壞事。

爲什麼你會希望淺拷貝與昂貴的拷貝+淺層移動的主要原因是其中拷貝不僅僅是「淺拷貝」的類型。例如,shared_ptr。複製不只是複製一個或兩個指針;你也會碰到參考計數。事實上,這是shared_ptr作爲一種類型的設計的結果:允許多個所有者爲一個對象。

而唯一的方法就是如果每個業主都有自己的副本。因此,在這方面,複製必須是「淺薄的」。

所以它的優勢在於它是對象設計的一部分。


如果您在談論pre-C++ 11天,淺拷貝更有意義。 Post-C++ 11,你可以依賴廉價的移動操作,但是C++ 11之前的版本不可用。所以淺拷貝幾乎是通過值合理返回對象的唯一方法。

+2

這是如何解決OP的理解:「如果你有一個只讀或不可變的對象,你只想使用一個引用」? –

+0

@barakmanos:引用什麼?你不能使用裸const char *,因爲它沒有你想要的行爲。 –

+1

嗯,我認爲OP是指結構或類。術語* shallow-copy *對於除此之外的任何其他內容是否有效? –

-2

我首先想到的是移動一個對象。

假設你在新的操作符中在類中分配了一個內存。

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    void destroy() 
    { 
     delete [] data; 
    } 

    A (const A& copy) 
    { 
     data = copy.data; 
    } 


    int* data 
} 

比讓我們說要複製這個對象。爲什麼不直接將指針複製到數據而是複製所有數據。

A calculateA() 
{ 
    A returnVal; 
    for (int i = 0; i < 50; i++) 
     returnVal.data[i] = i; 
    return returnVal; 
} 

在這種情況下,淺拷貝是有利的。

A (const A& copy) 
{ 
    data = copy.data; 
} 

A newA = calculateA(); 
// do stuff with newA 
newA.destroy(); 

我相信也會有其他一些原因。

要避免複製副本時的雙重刪除可以設置爲空。

#include <iostream> 
#include <utility> 

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    ~A() 
    { 
     if (data) 
     delete [] data; 
    } 

    A (A& copy) 
    { 
     data = copy.data; 
     copy.data = nullptr; 
    } 

    int* data; 
}; 


int main() 
{ 
    A aVal; 
    for (int i = 0; i < 50; i++) 
     aVal.data[i] = i; 

    A anotherVal = aVal; 

    int i = 10; 
    while (i--) 
     std::cout << anotherVal.data[i]; 
} 
+0

請解釋投票,以便我從錯誤中學習。 –

+0

「*在這種情況下,淺拷貝可以是有利的。」*你剛剛解釋了淺拷貝可以很容易被破壞*。因爲在你的情況下,你將嘗試刪除'data'數組*兩次*。 –

+0

這就是爲什麼我說「可以」,因爲這個問題也問「可能是什麼原因」。通過簡單的指針檢查就可以輕鬆避免。 –

0

想象一下下面的例子:

shared_ptr<T> p1(new T); 
... 
shared_ptr<T> p2 = p1; 

這裏P2是P1的淺表副本。你可以在這裏使用引用,但你不能如果你返回它:

shared_ptr<T> f() { 
    shared_ptr<T> p1(new T); 
    return p1; 
} 
+0

這將自動從。當然,在C++ 11中。 –

+0

在第二個例子中,但不是第一個例子。 –

+0

沒錯,但是OP的觀點仍然(可能)是有效的:你不必嚴格需要淺拷貝才能以合理的方式對對象進行操作。 –