2015-09-28 102 views
1

我有一個rapidjson包裝,做以下的不必要的副本:如何防止物體

class ADocument 
{ 
    void setJson(const char *data) { m_D.parse(data); } 

    AData operator[](const char *key) const 
    { 
     const rapidjson::Value *value = rapidjson::Pointer(key).Get(m_D); 

     if(value) 
      return AData(value); 
     else 
      return AData(&m_D); 
    } 

private: 
    rapidjson::Document m_D; 
}; 

AData類是這樣的:

class AData 
{ 
public: 
    Adata(const rapidjson::Value *val) : m_Value(val) {} 

    operator QString() const { return m_Value.IsString() ? m_Value.GetString() : QString(); } 

private: 
    const rapidjson::Value *m_Value; 
}; 

而且整個事情是這樣調用:

ADocument doc; 
doc.setJson("{\"Hello\":{\"Hello\":\"test\"}}"); 

QString str = doc["/Hello/Hello"]; 
str變爲 「測試」

現在,通過調試這個代碼我發現該AData對象以某種方式移動 - 的operator QString()會從在不同的存儲器位置的對象比原始AData對象調用中的ADocumentoperator[]構造。正則構造函數被調用一次。但可能是copy-elision只是在內存中移動相同的對象。

然而,當我定義的規則的三/ 5方法之一,如AData析構函數不改變任何東西(和析構函數什麼也不做本身),那麼operator QString()上調用同一對象(同一內存位置),其在ADocumentoperator[]中構建。

即使當我實現了所有可想象的構造函數和運算符(move,copy,assign ...)時,它們中的任何一個都不會被調用,但結果是相同的 - 只創建一個對象。

這是怎麼回事?我想了解它。

此外,如何改變這個實現,以便儘可能提高性能和內存效率(=最小副本等)?或者,也許我真的很擔心沒有什麼,我所看到的僅僅是一些編譯器優化?

+0

什麼是AConstData? –

+0

@AlanStokes對不起,錯字。我從我的源代碼複製了我實際上有兩個類AData和AConstData的代碼。我用後者進行了一些測試,但它們都是相同的。 – Resurrection

+1

聲音像複製elision正在按預期工作,有什麼問題?我認爲你不用擔心,應該讓編譯器完成它的工作。 –

回答

1

這是怎麼回事?我想了解它。

您正在使用複製elision

當一個未命名的臨時文件將被複制或移動到一個相同類型的變量中時,編譯器可以直接在該變量中構造該對象並跳過複製或移動操作。

您可能會遇到這種情況的另一種情況是當您從函數中返回具有自動存儲持續時間的變量時。