質問
私はこれについて前に関連する質問をしましたので、私は未定義の行動を知っています。
char char *をchar *に戻す。データを変更する
string _str = "SDFDFSD";
char* pStr = (char*)_str.data();
for (int i = 0; i < iSize; i++)
pStr[i] = ::tolower(pStr[i]);
.
私はこれについての私の同僚のうちの1つと議論をしました。そして彼は、データの長さを変更しない限り、このシナリオでは問題を引き起こすことはないと言った。データを変更したが、std::string
がデータが変更されたことを検出する方法がないため、問題を発生することは決してないでください。_str
のいずれかで内部の不整合性は発生しません。それは本当にそうですか?
解決
未定義の行動はあまりにも多くのことを恐れていました、そして鼻のデーモンへの言及はほとんどの人たちが他のものよりも神話だったことをほとんどの人に確信しているようです。
あなたの同僚がその問題の具体的な証明をもたらす必要があることを納得させるためにあなたの同僚が非常に脱感作されているようです。幸いなことに、あなたが手元にGCCを持っているならば、それは行うことができます:
#include <iostream>
#include <string>
int main() {
std::string const UPPER = "HELLO, WORLD!";
std::cout << "UPPER: " << UPPER << "\n";
std::string lower = UPPER;
for (char* begin = const_cast<char*>(lower.data()),
* end = begin + lower.size();
begin != end;
++begin)
{
*begin = std::tolower(*begin);
}
std::cout << "lower: " << lower << "\n";
std::cout << "UPPER: " << UPPER << "\n";
return 0;
}
.
gcc、を使う場合は、:
UPPER: HELLO, WORLD!
lower: hello, world!
UPPER: hello, world! // What the hell ? UPPER was const !!!
.
なぜですか?GCCは歴史的に write を使ったので、 chatered 以降、書き込みを検出せず、その下にあるストレージアレイが共有されています。
注:はい、これはC ++ 11で不適合ですが、C ++ 11で機能する機会がありました。
他のヒント
data()ドキュメント:
データを介してアクセスされる文字配列の変更は未定義の動作です。
だからあなたの同僚が間違っている、トリックはありません、それは未定義の行動です。何が起こるのは実装固有です。
悪い考え!必ず文字列が現在または将来のプラットフォームでどのように実装されているかを知ることはできません。たとえば、どういうわけか似ている他のオブジェクトとのストレージを共有することができます。データをいくつかのプラットフォームで読み取りセグメントに入れることができます。