在我開始討論肉食之前,讓我們介紹一下關於大多數字符串類的一些特別的事情。字符串類通常是作爲一種智能指針來實現字符串的緩衝區。這意味着:
std::string s1("testing");
std::string s2;
s2 = s1;
雖然S2是一個獨特的字符串類,分配s2 = s1
後,還有他們之間只有一個字符串緩衝區。該緩衝區不被複制,它以一種只讀配置共享。如果在s2中對字符串進行了更改,那麼此時會創建一個副本,以使兩個字符串指向不同的緩衝區。
你的問題可能不是關於緩衝區本身,而是操作這些緩衝區的字符串對象,但它在字符串(和類似的std :: shared_ptr出於類似的原因)的情況下切線相關,其中複製性能是關心。複製std :: string類通常比複製底層緩衝區要少得多。
也就是說,關於你的代碼示例,還有一點值得解決,那就是使用這些函數的返回值做的事情(部分原因是因爲你詢問了其中兩個函數中的字符串後面是什麼)。
重複與輕微擴張:
#include <string>
using namespace std;
string t1(string z) { return z; }
string *t2(string &z) { return &z; }
string& t3(string *z) { return *z; }
string& t4(string& z) { return z; }
string t5(string &z) { return z; }
int main() {
string s; string x; string *xp
x = t1(s);
xp = t2(s);
x = t3(&s);
x = t4(s);
x = t5(s);
return 0;
}
現在,重要的是要在功能擴展點t1時刻。有理論,並且有實際的結果,它們在所有現代C++編譯器中都有所不同。在考試中,我希望你會回答純粹的理論,忽略這些在這裏發揮作用的單項副本。考慮x = t1(s)
,其中理論上s被複製爲函數的參數,函數內的z是來自調用者的s的副本。回報是有價值的,因此理論上第二個副本被創建以返回。然後,理論上,當x被分配時執行另一個副本。現在,如果你在調試器中追蹤它,那也可能是你所見證的。但是,除了最天真的編譯器之外,所有這些副本都將被忽略,這樣x會收到s的副本,就好像編寫了x = s
(並且大多數編譯器會檢查這個文字代碼,意識到什麼都沒有完成,併發出一個程序不做任何事情,但返回)。
現在,約x = t2(s);
該參數是對字符串的引用(這些東西是從右向左解釋的,因此即使大多數人都說「字符串引用」,也應該認爲引用了字符串,這意味着函數沒有使用副本,它是調用者的函數,這個函數返回該字符串的地址,一個指針,這意味着沒有s的拷貝 - 我們至多會說一個指針的拷貝被返回,這與寫上xp = &s;
在x = t3(&s)
我們有一個好奇的例子,函數接受一個指針,它需要& s取s的地址來提供該指針,因此在函數調用時沒有s的副本,函數返回ar參照一個字符串(正如以前一樣,從右到左,儘管有些人可能會說一個字符串引用)。由於這是一個指針的解引用,所以結果只是通過它的地址引用s,並且在返回中沒有複製。迴歸是參考的事實進一步支持了這一點。引用是作爲一個指針來實現的。這是一種特殊的指針,但在引擎蓋下,它是一個指針 - 沒有複製。但是,由於x是一個唯一對象,因此在爲其分配x時,會從該引用的分配中進行復制。它解析爲同樣的事情寫過x = s;
有此功能支持值得分開考慮其它使用情況下:
string xr(t3(&s));
在這種情況下,參考用於初始化XR(基準時刻t3返回)。它類似於string xr(s);
。到目前爲止,不是一個啓示。但是,考慮使用返回的字符串與t2和t1進行比較。
t1(s).length();
t2(s)->length();
t3(&s).length();
這裏,每個函數的返回值都是用來調用字符串的成員。與t1的調用已將s複製到函數中,然後再次複製以返回臨時字符串,然後銷燬該字符串(將調用析構函數),這是您在查詢中沒有真正解決的一點。
然而,t2和t3的呼叫實際上是使用s作爲呼叫而沒有任何暗示的副本。然而,在t2情況下,該調用是通過指針。 t2的情況就像寫了(奇怪的)(& s) - > length(),而t3的情況與寫入s.length()的情況相同。
T4與t3完全相同,只是在調用的方式和與nullptr傳遞給t3的可能性相關的含義上有所不同(導致解除引用導致崩潰),「 t發生在t4。
T5與t4(和t3)的區別僅在於,由於按值返回而隱含副本。返回的結果與t1類似,像t1一樣運行,並且僅與t1不同,暗示t5不會爲函數體創建一個副本,它只會爲返回創建一個副本。
假設你提供的,呼叫到t5之後追加主要示例代碼:
string a, b;
// t1 is like having written:
a = s;
b = a;
x = b;
// t5 is like having written:
b = s;
x = b;
含義,t1的第一副本由以下事實T5消除需要引用,而不是一個值。
在現代C++中,我們通常忽略理論在t1或t4,t5等情況下的性能含義。我們更關心爲什麼使用引用而不是副本,因爲使用引用的副作用是函數t5中的字符串對調用者所做的更改,而副本隱含在t1中並且因此呼叫者的狀態不會改變。這是你問題的重要組成部分。
如上所述,理論將始終創建副本被寫入的副本,但實際上由於優化,副本被省略(避免)。例如,在t1的情況下,文字代碼將隱含所有隱含副本 - 不會執行副本。但是,如果在t1的函數體內對z進行了更改,則會改變事物。如果對t1進行更改,編譯器會意識到改變z的副作用將會改變s,除非進行了複製,這意味着將創建一個由傳值參數t1所暗示的副本,以避免副作用,但仍然隱藏了按價值回報所隱含的副本。
那麼究竟什麼是你的問題?請編輯您的帖子,並提供一些關於您希望我們如何幫助您的說明。 –
這真的很寬泛;你在用什麼C++書?如果你花一些時間閱讀它,你會學到這些語言的基礎知識。 –