2011-04-20 7 views
9

私のコードは次のようである:予想通り変更根底にあるchar配列は

I gccを使用して、上記のスニペットをコンパイル

    string s="abc"; 
    char* pc = const_cast<char*>(s.c_str()); 
    pc[1]='x'; 
    cout << s << endl; 

が、私は結果「AXC」を得ました。私の質問は、このようにC++の文字列の基本的なchar配列を変更することは安全で移植性があるということですか?あるいは、文字列のデータを直接操作する代替の方法があるかもしれませんか?

参考のため、私は、cとC++の両方で呼び出せる純粋なc関数を書くつもりです。したがって、引数としてchar *だけを受け入れることができます。 char *からstringへ、コピーが含まれていることを知っていますが、ペナルティは好ましくありません。ですから、誰もこの種の状況に対処するための提案をすることができます。

答えて

1

これは未定義の動作に依存しているため、移植性がありません。

0

基本文字列を混乱させるべきではありません。一日の終わりに、文字列はオブジェクトです、このように他のオブジェクトを混乱させるでしょうか?

あなたのコードをプロファイリングして、ペナルティがあるかどうかを確認しましたか。

4

(a)これは必ずしも基本となる文字列ではありません。 std::string::c_str()は、基になる文字列のコピーでなければなりません(C++標準のバグは、実際にはそうではないことを意味します...これはC++ 0xで修正されていると思います)。

(b)const_cast constを無視すると、実際のオブジェクトはまだconstであり、未変更の動作—が非常に悪いです。

単純に言えば、ではなく、となります。


&myString[0]はまったく使用できますか?それは非constバージョンを持っています。再び、非constバージョンを持たないdata()[0]と同じであると述べられています。まともなライブラリ参照を手に持つ人がこれをクリアすることができます。

+0

したがって、&mystring [0]は安全な方法ですか? – Need4Steed

+0

@ Need4Steed:並べ替え。 C++ 98/C++ 03では、文字列の内容が技術的に連続的であることは保証されていません...しかし、標準のバグはすべての主流の実装がどうにか連続していることを意味し、これはC言語で標準化されました++ 0x。 (あなたが得たポインタはnull終端されたchar配列を指していないので、その長さも渡す必要があることに注意してください。) –

+0

はい、最新の基準があります。また、実装されていない実装はありません。しかし、予約された長さをオーバーランしないように注意してください。 – Coder

1

これはお使いのオペレーティングシステムによって異なります。 GNU libcライブラリではstd::stringcopy-on-write (CoW) patternを使って実装されています。したがって、複数のオブジェクトが最初に同じ内容を含む場合、内部ではすべて同じデータを指します。したがって、あなたがあなたの質問に表示する方法でそれらのいずれかを変更すると、(一見)無関係のstd::stringオブジェクトのすべての内容が変更されます。

Windowsでは、実装がCoWを使用しないと思いますが、何が起こるかわかりません。

とにかく、それは未定義の動作ですので、私はそれを明確にします。たとえそれを稼働させても、最終的には追跡が困難なバグに遭遇する可能性があります。

4

c_str()const char*を返します。この場合、const_castはすべて、未定義のビヘイビアがコンパイルされることがあります。

2番目の部分では、C++ 0x std::stringは、C++ 03のstd::vectorのように連続した記憶域を持つことが保証されています。したがって、&s[0]を使用すると、文字列が空でない限り、char*を関数に渡すことができます。実際には、現時点で開発中のすべてのstringの実装には、すでに連続したストレージがあります。標準的な委員会でストローの投票があり、誰も反例を提示していませんでした。この機能は、好きなときに使用できます。

しかしstd::string、すなわち、それはデータ+長ではなく、ヌル文字で終了だ、C形式の文字列から根本的に異なる文字列形式を使用しています。 C関数から文字列データを変更した場合、文字列の長さを変更することはできません。末尾にヌルバイトがあることを確認することはできません。c_str()を使用しないでください。そしてstd::stringにはデータの一部である埋め込みnulsが含まれている可能性があるので、長さを知らずにヌルを見つけたとしても、文字列の最後を見つけたことはまだ分かりません。あなたは、両方の種類のデータで正しく動作する関数でできることは非常に限られています。

2

他の人が言ったように、移植性がありません。しかし、より多くの危険性があります。いくつかのstd :: stringの実装(私はGCCがそれをしていることを知っています)COW(書き込み時にコピー)を使用します。

#include <iostream> 
#include <string> 

int main() 
{ 

    std::string x("abc"); 
    std::string y; 
    y = x; // x and y share the same buffer 

    std::cout << (void*)&x[0] << '\n'; 
    std::cout << (void*)&y[0] << '\n'; 

    x[0] = 'A'; // COW triggered 

    // x and y no longer share the same buffer 
    std::cout << (void*)&x[0] << '\n'; 
    std::cout << (void*)&y[0] << '\n'; 

    return 0; 
} 
+0

すべての 'std :: string'がコピーオンライトセマンティクスを使用するわけではありません。いくつかの実装では、 'std :: string'をコピーするときに基礎となる文字配列を深くコピーします。どのような場合でも、このような実装の詳細に頼るべきではありません。 –

+0

@In silico注目される。ありがとう。 – pic11

+1

最初の '&x [0]'はバッファをun-shareすることを期待します。ポインタを格納して後で使用するかどうかわからないからです。 'char * p = &x[0]; ...; * p = 'X'; 'y [0]'とは何ですか? –

1

明白な答えはいいえ、未定義の動作です。他の 逆に、あなたが行う場合:

char* pc = &s[0]; 

今日は実際には、基礎となるデータにアクセスすることができ、かつ はC++ 11で保証されています。

関連する問題