7

それはばかげた質問のように思われるかもしれませんが、私は本当にこれを明確にする必要があります:

これは私のプログラムに危険をもたらしますか?

const_castでも必要ですか?

入力ポインタの値を変更すると、安全に機能しstd::stringますか、それとも未定義の動作が発生しますか?

これまでのところ、唯一の懸念は、入力ポインタを変更して使用できなくするたびに、これが文字列「some_text」に影響を与える可能性があることです。

std::string some_text = "Text with some input";

char * input = const_cast<char*>(some_text.c_str());

ヒントをくれてありがとう、自分の足での撮影は避けたい

4

9 に答える 9

14

悪い振る舞いの例: gcc の Copy On Write 実装との相互作用。

#include <string>
#include <iostream>

int main() {
    std::string const original = "Hello, World!";
    std::string copy = original;

    char* c = const_cast<char*>(copy.c_str());
    c[0] = 'J';

    std::cout << original << "\n";
}

イデオンで活動中。

ジェロ、ワールド!

問題 ?名前が示すように、gcc の の実装はstd::string、内部で参照カウント共有バッファーを使用します。文字列が変更されると、実装はバッファが現在共有されているかどうかをきちんとチェックし、共有されている場合は、変更する前にコピーして、このバッファを共有している他の文字列が新しい書き込みの影響を受けないようにします (したがって、名前、コピーオンライト)。

さて、あなたの邪悪なプログラムでは、(何も変更しないことを約束して) const メソッドを介して共有バッファにアクセスしますが、実際に変更します!

コピー オン ライトを使用しない MSVC の実装では、動作が異なることに注意してください ("Hello, World!"正しく出力されます)。

これはまさにUndefined Behaviorの本質です。

于 2012-04-24T08:02:03.567 に答える
5

constを使用して constness をキャストすることにより、本質的にオブジェクトを変更することconst_castは、未定義の動作です。

string::c_str()は を返しますconst char *。つまり、C スタイルの定数文字列へのポインタです。技術的には、これを変更すると、未定義の動作が発生します。

const_castを使用するのは、非定数データへのconstポインタがあり、非定数データを変更したい場合であることに注意してください。

于 2012-04-24T07:48:16.710 に答える
4

単にキャストするだけでは、未定義の動作は発生しません。ただし、ポイントされたデータを変更すると、変更されます。(ISO 14882:98 5.2.7-7も参照してください)。

変更可能なデータへのポインタが必要な場合は、

std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];
于 2012-04-24T07:54:10.950 に答える
2

std::stringそれ自身のメモリを内部で管理します。そのため、関数の場合と同様に、そのメモリへのポインタを直接返しますc_str()。変更しようとするとコンパイラが警告するように、定数であることを確認します。

そのように const_cast を使用すると、文字通りそのような安全性が失われ、メモリが変更されないことが絶対に確実な場合にのみ、間違いなく受け入れられる方法です。

これを保証できない場合は、文字列をコピーしてそのコピーを使用する必要があります。; どのような場合でもこれを行う方が確かに安全です ( を使用できますstrcpy)。

于 2012-04-24T07:52:03.680 に答える
2

C++ リファレンスWeb サイトを参照してください。

const char* c_str ( ) const;

"文字列オブジェクトと同じ内容のヌル終了文字シーケンス (c-string) を生成し、文字配列へのポインターとして返します。

終了ヌル文字が自動的に追加されます。

返された配列は、この一連の文字に必要な記憶領域とその終端のヌル文字を含む内部の場所を指しますが、この配列の値はプログラムで変更してはならず、次の呼び出しまで変更されないことが保証されているだけです。文字列オブジェクトの非定数メンバー関数です。」

于 2012-04-24T07:52:05.830 に答える
1

これは非常に悪いことです。std :: string :: c_str()が何をするかをチェックして、私に同意してください。

次に、std::stringの内部への非定数アクセスが必要な理由を検討してください。どうやら、内容を変更したいのです。そうしないと、constcharポインターを使用するからです。また、元の文字列を変更したくないのではないかと心配しています。書いてみませんか

std::string input( some_text );

次に、元の文字列に影響を与えることなく混乱できるstd :: stringがあり、生のC++ポインタを操作する代わりにstd::string機能があります...

于 2012-04-24T07:55:55.190 に答える
1

はい、それは危険をもたらします。

  1. inputc_str現在起こっていることは何でも指しsome_textますが、変化したりなくなったりすると、ガベージを指すポインターが残ります。の値はc_str、文字列が変更されない限り有効であることが保証されています。さらに、正式には、他の文字列も呼び出さない場合に限りますc_str()
  2. const をキャストする必要があるのはなぜですか? あなたは に手紙を書くつもりはありません*inputよね?それはノーノーです!
于 2012-04-24T07:51:35.197 に答える
1

これに関するもう 1 つの解釈は、コードの保守が非常に困難になるということです。適切な例: 数年前、長い関数を含む一部のコードをリファクタリングする必要がありました。作成者は const パラメーターを受け入れる関数シグネチャを作成しましたがconst_cast、constness を削除するために関数内でそれらを ing していました。これにより、関数によって与えられた暗黙の保証が破られ、残りのコード本体内でパラメーターが変更されたかどうかを知ることが非常に困難になりました。

要するに、文字列を制御していて、それを変更する必要があると思われる場合は、最初から非 const にします。そうでない場合は、コピーを取り、それを操作する必要があります。

于 2012-04-24T08:02:16.247 に答える
1

UBです。たとえば、次のようなことができます。

size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];

キャストなしでコミラーはエラーを報告しません。しかし、このコードは違法です。士気は、毎回行動を考える必要があるということです。

于 2012-04-24T08:39:10.083 に答える