2016-11-06 30 views
3

如果編譯器會在以下情況下優化副本,我會漫步。我有一個類,其唯一的資源成員是可能是幾KB的字符串。我想有一個這個類的公共成員來訪問該字符串,我不知道我是否應該讓這個成員返回一個引用或僅僅是通過值。假設我選擇的價值,像這樣當返回一個字符串作爲const引用時,編譯器是否避免了一個副本?

class A { 
    public: 
    A(); 
    ~A(); 
    std::string getString() { return str; } 
    private: 
    std::string str; 
} 

int main() { 
    A *a = new A; 
    const std::string& str = a->getString(); 
    std::cout << str; 
} 

返回編譯器優化和將避免副本,如果我把結果作爲const std::string&main

+0

我不明白你爲什麼認爲編譯器*不會*避免複製。調用者要求對字符串進行「const」引用,那麼爲什麼編譯器不提供這些? – EJP

回答

2

這是遠程可能的,但編譯器在此用例中優化掉副本的可能性非常小。

觀察到,如果副本得到優化,則調用者的臨時實際上被綁定爲對對象的類成員的const引用。而const表示參考值不能更改。

僅使用此問題中顯示的代碼,編譯器可能會證明自己沒有任何可以更改類成員的內容,而const引用保留在範圍內,因此可以安全地進行此優化。

但事情變得很渾濁,在一個更普遍的情況下。如果有其他類方法可能會改變被引用類成員的內容,那麼在const引用的生存期內有任何調用的函數或方法的定義不可見;最可能的結果是編譯器無法知道引用的類成員是否可能在const引用的整個執行範圍內被修改,因此它將被迫複製字符串以便保證其const性。

編譯器可以自由地只進行那些導致在格式良好的程序中沒有可見的觀察到的變化的優化。如果編譯器無法證明優化結果沒有可見的可觀察的變化,那麼優化將不會執行。

P.S.請注意,「修改」還包括銷燬。建議的優化將const引用綁定到動態範圍內的對象。如果對delete有任何干預調用 - 顯式或隱式地作爲對各種庫容器方法的調用的一部分 - 編譯器還必須證明自己delete d對象不能是具有約束const引用的對象。

+0

謝謝,但是如果'A'的成員也被聲明爲'const',怎麼樣? (我可以用一個委託構造函數初始化它)從我的答覆我推斷,編譯器可能會優化此副本,因爲它可以保證我傾向於同意它的「常量」 –

+0

,受我的P.S. - 編譯器只需證明該對象在綁定的'const'引用範圍內不能被銷燬。 –

+0

我認爲這還不夠。您可以在複製完成後將對象分頁出去而不實際銷燬它,編譯器將很難知道會發生什麼情況。 – Dani

相關問題