2012-05-13 71 views
8

我的同事的代碼是這樣的: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

但是旁邊的其他人說過去有關於這是合法的討論。任何人都可以請爲我清除這個?

+0

我會更關心目標指針。爲什麼這個函數沒有大小參數? – LaC

+0

也許你應該嘗試複製's.c_str()',如果你想在複製空終止符... – Yaniro

+3

也許'd'有錯誤的容量 – Abyx

回答

10

讓我們拋開可能性,即*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()。否則,行爲是不確定的。

由於在示例代碼sconst,行爲被很好地定義和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:stringi < s.size()。現在是不確定的行爲?我懷疑該條款僅適用於特殊情況charT()對象。

另一個有趣的事情是,兩種標準似乎都不要求爲s[s.size()]返回的對象的地址與以s[s.size() - 1]返回的對象的地址有任何關係。換句話說,看起來返回的charT()引用不必與字符串數據的末尾連續。我懷疑這是爲了給實現者一個選擇,如果需要的話,只返回一個引用到該哨兵元素的單個靜態副本(這也可以解釋C++ 11的「不得修改」限制,假設它僅適用於特殊案件)。

+0

我發現'at'有趣,但是,不允許以'size()'作爲索引來調用。 –

+0

感謝您的深度分析。 –

7

cppreference says this:

reference  operator[](size_type pos); 

const_reference operator[](size_type pos) const; 

如果pos==size()

  • const版本返回到與值表()(空字符)的字符的參考。 (直到C++ 11)
  • 兩個版本都返回對值爲CharT()(空字符)的字符的引用。通過非const引用修改空字符會導致未定義的行爲。 (因爲C++ 11)

所以這是OK,只要你不修改的空字符。

+0

OP的代碼不會嘗試修改std :: string,它會嘗試從字符串讀取並將其放入char數組中。 –

+4

需要說明的是,如果使用C++ 11之前的編譯器,如果s不是const,那麼對[s.size()]的訪問是不確定的 - 只能在問題代碼中訪問因爲's'是'const'(對於C++ 11之前的編譯器)。它與null字符是否被修改無關,只是's'是否是'const'。當然,這些都沒有提到任何關於'* d'可能無效的可能性。 –

+1

我覺得引用一個網站來證明標準符合性很有意思,讓我挖一下;) –

0

如果你想那樣做(你collegue的代碼試圖複製終止\0爲好),你可以

  • 使用c_str()
  • i < s.size()一起使用循環,然後手動追加\0

編輯:
好,由其他的答案來看,我更傾向於現在認爲Abyx的評論是正確的:數組d可溢出(或者甚至有可能不會被分配)。先檢查一下。
但是請確保您也複製\0

相關問題