または、それらを変更することに対する他の保護がありますか?
それらが読み取り専用メモリにある場合は理にかなっています-それがそれらを作成する理由const
ですよね?
const
はコンパイル時の構造であり、実行時には不明です。プログラマーが自分のプログラムについて推論するのを助け、変更されるべきではないものを変更することによってバグが導入されるのを防ぐためだけに存在します。 const
この変数の変更を許可しないことをコンパイラーに伝え、コンパイラーはそれを強制します。
いいえ、そうである必要はありません。const
コンパイル時であり、コンパイラが何らかの最適化を実行できるようにします。ただし、変数を読み取り専用のメモリ ロケーションに配置することは必須ではありません。
Undefined Behaviorであるこの例を参照してください(指摘してくれた Dyp に感謝します)。
#include <iostream>
int main()
{
const int bla = 42;
int *ptr = const_cast<int *>(&bla);
std::cout << *ptr << std::endl;
*ptr = 21;
std::cout << *ptr << std::endl;
}
42
とが出力されます21
が、クラッシュする可能性もあります。
これを見てください:
#include <iostream>
int main()
{
const int bla = 42;
int *ptr = const_cast<int *>(&bla);
std::cout << bla << std::endl;
*ptr = 21;
std::cout << bla << std::endl;
}
私のコンパイラでは、コンパイラがいくつかの最適化を行ったため、この出力42
と. 42
が原因でクラッシュする可能性があることに注意してください*ptr = 21
。
コンパイラが aconst
を読み取り専用メモリにすることができない場合がたくさんあります (そもそもシステムに読み取り専用メモリがあると仮定して)。実際、ほぼすべてのコンパイラは、原則として、const
通常の変数と同様に、オブジェクトを通常のデータ (またはスタック) メモリに格納すると考えています。
の主な目的はconst
、値を変更したくない、または変更することを想定していない意図をコンパイラで宣言することです。const
限られた状況下で、コンパイラが変数を読み取り専用メモリに配置できない理由はわかりません。しかし、私もこれに依存しません-標準は確かにこれを可能にします。最初にマークされたオブジェクトからconst_cast
removeを使用し、それに書き込むことは未定義の動作であると述べているためです(したがって、コンパイラがを使用して元の値を削除した後に値を変更できるようにするため、「読み取り専用メモリに書き込もうとしたためクラッシュ」が発生する可能性があります)。const
const
const_cast
const
しかし、これを考慮してください:
class X
{
int x;
public:
X(int v) : x(v) {}
}
int c = rand();
const X a(c+1);
const X b(c+2);
この場合、コンパイラはc
から取得した の値を認識できないため、コンパイル時にrand
初期化a
およびコンパイルできません。b
このconst
キーワードには、次の 2 つの用途があります。
const
限り、定義が読み取り専用メモリにあるオブジェクトを配置できます。mutable
そのためconst_cast
、const 修飾子を削除することは許可されていませんが、オブジェクト定義自体がそうではないことが要件ですconst
。ウィキペディアの const の正確性については、「ただし、それ自体が const として宣言されているオブジェクトを const_cast を使用して変更しようとすると、ISO C++ 標準に従って未定義の動作が発生する」と記載されています。
C++ 標準は、オブジェクトが読み取り専用メモリにあることを保証していないだけでなくconst
、以下で説明するように、実装を完全に実装することは困難です。
C++ 実装const
では、アドレスが読み取り専用メモリに取得される自動保存期間を持つオブジェクトを配置することは困難です。これは、それぞれのオブジェクトが異なるアドレスを持つ必要があるためです (それらのポインターが等しくない必要があるため)。したがって、そのような各オブジェクトは、それが含まれるブロックが実行されるたびに作成する必要があります。
もしconst
オブジェクトのアドレスが取得されない場合、コンパイラはメモリ内の単一のインスタンスのみを使用して (C++ 計算モデルで) 複数のインスタンスを実装できます (すべてのインスタンスは同一であり、変更されないため)。そのため、このようなオブジェクトは、プログラムの起動時に (おそらくプログラム ファイルの定数データ セクションからロードすることによって) 1 回作成し、読み取り専用としてマークし、プログラムの実行中はそのままにしておくことができます。ただし、オブジェクトのアドレスが取得される (そして観察可能な方法で使用される) 場合、コンパイラはオブジェクトの個別のインスタンスをそれぞれ作成する必要があります (または、1 つのインスタンスが複数のアドレスを持つように「偽造」する必要があります)。一般に、コンパイラは、ブロックの実行が同時にいくつ存在するかを予測できません (たとえば、再帰的な関数呼び出しがある場合)。したがって、プログラムの起動時に、必要なオブジェクトのすべてのインスタンスを作成することはできません。
オブジェクトを作成するには、オブジェクトの初期値を書き込むためにメモリを変更する必要があります。したがって、const
自動保存期間を持つオブジェクトを読み取り専用メモリに配置するには、メモリを読み取り専用から書き込み可能に、またはその逆に頻繁に変更する必要があります。新しいオブジェクトを作成するには、プログラムは読み取り専用メモリを書き込み可能メモリに変更し、新しいオブジェクトの初期値を書き込み、メモリを読み取り専用に戻す必要があります。
さらに、これにより、シグナル ハンドラのないシングル スレッド プログラムに対してのみ、読み取り専用メモリのように見えます。複数の実行スレッドまたは単一のハンドラーを持つプログラムは、書き込み可能な状態にある間、メモリを監視できる場合があります。
標準に関する限り、const
書き込み保護された RAM に変数を配置する必要はありません。const
基本的には、コンパイラが強制するドキュメントにすぎません。
実際には、コンパイル時に値を完全に計算できる場合、コンパイラは通常、const
変数に対して読み取り専用ストレージを使用します。それ以外の場合は、他のすべてのものと同じ読み取り/書き込みヒープまたはスタックに配置されます。
いいえ。メンバーを持つconst
オブジェクトを検討してください。mutable
前述のように、const は、プログラマーが意図を伝えるのに役立つコンパイル時の構成要素です。
const
はコンパイラのマークです。コンパイル中に、コンパイラは定数を別のグループに追加し、それを変更しようとする試みをチェックします。一部の関数がそれを行おうとすると、コンパイラ エラーが発生します。
ただし、ポインターを使用してコンパイラーをだまして値を変更することは可能ですが、その結果、コンパイラーではなく自分 (または同僚) をだますことになります。const
const_cast
const
私が言ったように、価値を変える方法を探していた私の友人に。const
コンパイラ専用ではなく、コンパイラよりも開発者向けです。どのデータが変更されないかを示しているからです。
それらが読み取り専用メモリにある場合、有用で意味のあるものになることが妨げられるためconst_cast
、次のようなコードは不可能であり、const
変数を非const
パラメーターで関数に渡します。
void print (char * str)
{
cout << str << endl;
}
int main ()
{
const char * c = "test text";
print ( const_cast<char *> (c) );
return 0;
}
print 関数は、最初に定義されたconst
variableの値を実際に変更する可能性があることに注意してくださいc
。