我的同事的代碼是這樣的:C++中的字符串[length()],可以嗎?
void copy(std::string const& s, char *d) {
for(int i = 0; i <= s.size(); i++, d++)
*d = s[i];
}
他的應用程序崩潰,我認爲這是因爲這個訪問s
超出範圍,因爲條件應該只到s.size() - 1
。
但是旁邊的其他人說過去有關於這是合法的討論。任何人都可以請爲我清除這個?
我的同事的代碼是這樣的:C++中的字符串[length()],可以嗎?
void copy(std::string const& s, char *d) {
for(int i = 0; i <= s.size(); i++, d++)
*d = s[i];
}
他的應用程序崩潰,我認爲這是因爲這個訪問s
超出範圍,因爲條件應該只到s.size() - 1
。
但是旁邊的其他人說過去有關於這是合法的討論。任何人都可以請爲我清除這個?
讓我們拋開可能性,即*d
是無效的,因爲這無關什麼這個問題似乎是衝着:無論是否在指數std::string::size()
訪問「元素」的時候std::string operator[]()
有明確定義的行爲。
的C++ 03標準品具有string::operator[]()
下面的描述中(21.3.4 「basic_string
元素訪問」):
const_reference operator[](size_type pos) const; reference operator[](size_type pos);
返回:如果
pos < size()
,返回data()[pos]
。否則,如果pos == size()
,const版本返回charT()
。否則,行爲是不確定的。
由於在示例代碼s
是const
,行爲被很好地定義和s[s.size()]
將返回一個空字符。但是,如果s
不是const string
,則行爲將是未定義的。
C++ 11彌補了const
版本的這種奇怪行爲在此邊緣情況下的行爲與非const版本行爲的差異。 C++ 11 21.4.5 「basic_string
元素訪問」 說:
const_reference operator[](size_type pos) const; reference operator[](size_type pos);
要求:
pos <= size()
。返回:
*(begin() + pos
)如果pos < size()
,否則參考 到類型T的對象與值charT()
;參考值 不得修改。
因此,對於C++ 11編譯器,無論string
是否爲const
,行爲都是明確定義的。
與這個問題無關,我覺得有點奇怪,C++ 11說「引用的值不應該被修改」 - 我不清楚這個子句是否僅適用於pos == size()
的情況。我很確定有很多現有的代碼可以執行諸如s[i] = some_character;
的工作,其中s
是非常量的std:string
和i < s.size()
。現在是不確定的行爲?我懷疑該條款僅適用於特殊情況charT()
對象。
另一個有趣的事情是,兩種標準似乎都不要求爲s[s.size()]
返回的對象的地址與以s[s.size() - 1]
返回的對象的地址有任何關係。換句話說,看起來返回的charT()
引用不必與字符串數據的末尾連續。我懷疑這是爲了給實現者一個選擇,如果需要的話,只返回一個引用到該哨兵元素的單個靜態副本(這也可以解釋C++ 11的「不得修改」限制,假設它僅適用於特殊案件)。
我發現'at'有趣,但是,不允許以'size()'作爲索引來調用。 –
感謝您的深度分析。 –
reference operator[](size_type pos); const_reference operator[](size_type pos) const;
如果
pos==size()
,
- const版本返回到與值表()(空字符)的字符的參考。 (直到C++ 11)
- 兩個版本都返回對值爲CharT()(空字符)的字符的引用。通過非const引用修改空字符會導致未定義的行爲。 (因爲C++ 11)
所以這是OK,只要你不修改的空字符。
OP的代碼不會嘗試修改std :: string,它會嘗試從字符串讀取並將其放入char數組中。 –
需要說明的是,如果使用C++ 11之前的編譯器,如果s不是const,那麼對[s.size()]的訪問是不確定的 - 只能在問題代碼中訪問因爲's'是'const'(對於C++ 11之前的編譯器)。它與null字符是否被修改無關,只是's'是否是'const'。當然,這些都沒有提到任何關於'* d'可能無效的可能性。 –
我覺得引用一個網站來證明標準符合性很有意思,讓我挖一下;) –
如果你想那樣做(你collegue的代碼試圖複製終止\0
爲好),你可以
c_str()
。i < s.size()
一起使用循環,然後手動追加\0
。編輯:
好,由其他的答案來看,我更傾向於現在認爲Abyx的評論是正確的:數組d
可溢出(或者甚至有可能不會被分配)。先檢查一下。
但是請確保您也複製\0
!
我會更關心目標指針。爲什麼這個函數沒有大小參數? – LaC
也許你應該嘗試複製's.c_str()',如果你想在複製空終止符... – Yaniro
也許'd'有錯誤的容量 – Abyx