Const storageの仕組みに関する投稿を読みました。
constストレージはどのように機能しますか?(アイテム2、Scott Myers Effective C++)
これは、各セグメントに書き込み保護されたメモリの個別のセクションがあり、constデータがそこに送られることを示しています。
しかし、参照の場合はどうなりますか? 3つのシナリオを理解したいと思います。
そして、その問題のポインターについては、ポインターがいくつかの書き込み保護されたセクションに格納できるとしても、constの異なるバージョンがどのように維持されるかを意味します。
といった
char x = 'z';
//following can not change the data of x, but ptr itself can change.
const char* ptr = &x;
char y = '9';
ptr = &y;
上記は許可されていますが、以下は許可されていません
char* const ptr1 = &x;
ptr1 = &y;
これはどのように処理されますか?
C++のconst
には2つの側面があります。
論理的整合性:変数を作成してconst
ポインターまたはその参照をポイントすると、コンパイラーは、直接または間接的にconst
ポインターまたは参照を介して変数を変更しないことを単にチェックします。この一定性はconst_cast<>
でキャストできます。そのため、次のコードは完全に合法です。
char myString[] = "Hallo Welt!"; //copy the string into an array on the stack
const char* constPtr = myString;
const_cast<char*>(constPtr)[i] = 'e'; //perfectly legal
物理定数:const
である静的ストレージに変数を作成すると、コンパイラーが書き込み不可のメモリーに配置できるようになります。そうする場合とそうでない場合があります。標準に関する限り、そのようなオブジェクトを変更するためにconstnessをキャストする場合は、未定義の動作を呼び出すだけです。これにはすべての文字列リテラルが含まれるため、次のコードは機能する場合と機能しない場合があります。
const char* myString = "Hallo World!";
const_cast<char*>(myString)[1] = 'e'; //Undefined behavior, modifying a const static object!
以下の場合のように修飾子constを使用する場合:
const int value=67;
変数「value」の値を変更しないことを約束することをコンパイラーに伝えています。そのため、コンパイラーは「値」のインスタンスを初期化した実際の値に置き換えるだけです。コンパイラーは変数の各インスタンスを実際の値に置き換えるため、初期化する必要があります。
const int k; //error,must be initialized.
そのような値を参照にバインドする場合、参照(lvalue参照)を介してバインドされた値を変更しないように、参照にはそのような修飾子が必要です。
const int& c1=value;
c1=56; //error,we cannot modify it through the reference.
しかし、非const値をconst参照にバインドすることもできます...
int i=89;
const int& ic=i; //const lvalue-ref
int& ir=i;
ir=7; //ok.ir is not const
ic=67990; //error ic is const
ポインタについて:
const int val=90;
int* valp=&val;//error the pointer is not const.
const int* val2p=&val;//ok as they are both const
*val2p =788;//error as it is a pointer to non-writable space
ただし、constへのポインターを使用して、非constオブジェクトを指すことができます。constへのポインターと参照は、「constオブジェクトを指すか参照することを考える」という考え方です。
参照とは異なり、ポインターはオブジェクトであり、constにすることができます。ポインタが特定のメモリを指すようにでき、一度初期化されると別のメモリを指すことができないことを意味します。
int* const x=&val;//it will point to that memory location only.
「x」自体がポインターであるという事実は、それが指す値については何も述べていません。
もう1つの興味深いケースは、「constexpr」のケースです。
constexpr int* i=nullptr; //it is the pointer that is const.not the value it points to
constexpt const int* ii=&value; //both are const in this case.
厳密に言えば、const x
は単に、コンパイラにコンパイル時にチェックするを求め、初期定義の後でxを変更しないことを要求します。これは、プログラムの実行時の動作に対する変更や、xの値を別の方法で格納する必要があることを意味するものではありません。スマートコンパイラーは一部の最適化でそれを利用しようとしますが、一般的な場合、const値、ポインター、または参照に対して生成するマシンコードは、非const値、ポインター、または参照の場合とまったく同じになる場合があります。 const char*
とchar* const
の唯一の違いは、コンパイラが異なるチェックを実行することです。
実際、ここでの主な最適化は、静的な読み取り専用プログラムメモリに「const変数」を配置するのではなく、そこにリテラル値を配置することです。指定したサンプルでは、const
キーワードをどの変数で使用したか、使用しなかったかに関係なく、コンパイルされたバイナリのどこかに「z」と「9」の文字が存在する可能性があります。より長い文字列を使用する場合は、16進エディタを使用して、バイナリでそれらを簡単に見つけることができるはずです。
そのリテラルをconst x
に割り当てると、コンパイラはおそらくx
をメモリ内の別の場所として表現しないという追加の最適化を実行し、代わりにx
のすべての読み取りを解釈しようとしますプログラムコード内のそのリテラル値の読み取りとして。しかし、xがconstでない場合でも、何も割り当てないことが確認できるため、おそらくそうしようとします(割り当てられていない場合、xのconst
- nessを宣言する場合はconst
)。また、メモリからの読み取りをまったく回避するために、CPUレジスタにいくつかの中間値も格納しているため、実際のマシンコードは大幅に変動します。
C++機能のlotが同じように機能することは注目に値します。クラスメソッドがプライベートであることも、コンパイル時のチェックにすぎません。
Constキーワードは、初期値が変更されないことをコンパイラに指示します。コンパイラは、コンパイル中にプログラムが何らかの方法で値を変更しているかどうかをチェックします。定数変数と書き込み保護変数についての理解を明確にしてください。教科書の「変数」の定義に似ています
プログラミングでは、変数は、条件またはプログラムに渡される情報に応じて変化する可能性のある値です。通常、プログラムは、コンピュータに何をすべきかを指示する命令と、プログラムの実行中にプログラムが使用するデータで構成されます。
しかし、実際には変数はメモリの場所に付けられた名前であり、定数でもかまいません。