web-dev-qa-db-ja.com

不変とconstの違い

immutableconstという用語が同じ意味で使用されることはよくあります。ただし、私の(少しの)経験から、この2つはコードで行う「契約」が大きく異なります。

イミュータブルは、このオブジェクトが変更されない変更されるという契約を行います(たとえば、Pythonタプル、Java文字列)。

Constは、このvariableのスコープでは変更されないという契約を結んでいます(この期間中に指定されたオブジェクトに対して他のスレッドが実行する可能性については、C/C++キーワードなどの約束はありません)。

言語がシングルスレッド(PHP)であるか、線形型または一意型の入力システム(Clean、Mercury、ATS)を備えている場合を除き、2つは明らかに同等ではありません。

まず、これらの2つの概念に対する私の理解は正しいですか?

第2に、違いがある場合、それらがほとんど独占的に交換可能に使用されるのはなぜですか?

30
K.Steff

この違いが最も関連するC++について説明します。

お気づきのとおり、immutableは、オブジェクトの作成後にオブジェクトをまったく変更できないことを意味します。この作成はもちろん実行時に発生する可能性があります。つまり、constオブジェクトは必ずしもコンパイル時の定数ではありません。 C++では、(1)と(2)または(3)のいずれかが満たされた場合、オブジェクトは不変です。

  1. mutableメンバー関数によって変更されるconstと宣言されたメンバーはありません

  2. constとして宣言されています

  3. constメンバー関数は、const_castを使用してconst修飾を削除せず、メンバーを変更しません

ただし、アクセス修飾子を検討することもできます。操作がインスタンスを内部で変更しても、そのパブリックインターフェースを介して監視可能なインスタンスの状態に影響がない場合、オブジェクトは「論理的に不変」です。

したがって、C++は不変オブジェクトの作成に必要なツールを提供しますが、C++のほとんどすべてと同様に、ツールは最小限で十分であり、実際に使用するには注意が必要です。 C++は参照の透過性を強制する方法を提供しないため、インスタンスの状態は必ずしもインスタンスメンバー変数に限定されるわけではなく、グローバルまたはクラスの状態を含めることもできます。

constには、C++に別の関数(参照とポインターを修飾する)もあります。 const参照は、const以外のオブジェクトを参照する場合があります。 const_castを使用してconst参照、ifおよびを介してオブジェクトを変更することは、そのオブジェクトが宣言されていない場合にのみ合法です-const

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

そしてもちろん、constオブジェクトを変更することは未定義の動作です:

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
15
Jon Purdy

Javaの場合、キーワード "final"は "const"を表します)、

_final Person someone = new Person();
_

つまり、someoneは別のPersonオブジェクトを参照できません。ただし、紹介される人物の詳細を変更することはできます。例えば。 someone.setMonthlySalary(10000);

ただし、someoneが「不変」オブジェクトの場合、次のいずれかが当てはまります。(a)setMonthlySalaryという名前のメソッドがない場合(b)setMonthlySalaryを呼び出すと、常に例外がスローされますUnsupportedOperationExceptionなど

20
rationalrevolt

不変オブジェクトは、作成後に状態が変化しないオブジェクトです。例えば;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

この例では、myComplexStrオブジェクトは不変ですが、値が計算されるため、定数ではありません。また、これは文字列であり、静的な長さプロパティを持ち、変更できないため、不変です。

Constオブジェクトは通常、Pi、「USA」、「StackOverflow.com」、ポート番号など、コンパイル前に値がわかっている実際の定数を識別するために使用されます。

この観点から、Constは、値がプログラムによって計算されないため、Immutableオブジェクトとは異なります。

しかし、C++で「const」キーワードについて話している場合、「const」は不変オブジェクトの作成に使用されていると言えます。

10
Mert Akcakaya

まず、これらの2つの概念に対する私の理解は正しいですか?

はい、しかし2番目の質問は、これらの違いを理解していないことを示しています。

第二に、違いがある場合、それらがほとんど独占的に交換可能に使用されるのはなぜですか?

C++のconstは、アクセスレベル(「読み取り専用」を意味します)にのみ使用され、不変性ではありません。アクセス自体がデータから完全に分離されていることを意味します。たとえば、一部のデータを操作してから、const参照を通じてそれを公開できます。アクセスは読み取り専用ですが、データ自体は、すべてのデータが変更可能であるためです。

constは保証アクセス制限のみですが、不変性(たとえば、Dのような)は、オブジェクトの存続期間のどの段階でもデータを変更する方法を意味しません

これで、一部のデータがconst以外の方法でアクセスできないことを確認し、初期化されてもう触れられないことを確認することで、C++の不変性をシミュレートできます。しかし、Dのような言語では、データを不変としてマークするときに、これは強力な保証ではありません。言語は、そのデータを変更する操作をまったく実行できないことを確認しますが、C++では、本当に必要な場合は、constキャストと可変性によってデータを変更できる可能性があります。

結局、それはまったく同じ保証を提供しないので、それはまったく同じではありません

10
Klaim

JavaScriptと言えば、キーワードconstおよびObject.freeze

constbindings variablesに適用されます。不変のバインディングを作成します。新しい値を割り当てることはできません。

Object.freezeはオブジェクト値に対して機能します。オブジェクトを作成しますimmutable。つまり、そのプロパティを変更することはできません。

3
zangw

C++でも同じです。ただし、constオブジェクトは、メモリ内の場所と、そのメモリに書き込むためのOS権限があれば変更できます。

0
Martin Beckett

C、C++および関連言語では、constであるオブジェクトと、定数参照であるオブジェクトへの参照またはポインターとの間にも違いがあります。

定数オブジェクトを変更しようとすると、未定義の動作が発生します。 (たとえば、tryを使用して、定数オブジェクトを変更するには、そのアドレスを取得し、そのアドレスを非constポインターにキャストし、その非constポインターを使用してオブジェクトを変更します)。

一方、定数ポインタまたは参照は、このポインタまたは参照を使用してオブジェクトを変更できないことをコンパイラに伝えます。ポインタまたは参照をキャストして、オブジェクトを変更することができます。オブジェクト自体が一定だった場合、悪いことが起こります。オブジェクトが実際に一定でなかった場合、それは変化します。もちろん、これはコードのユーザーを混乱させ、バグを引き起こす可能性があります。

Cでは、「Hello」のような文字列リテラルを使用する場合、5文字と末尾の0バイトは実際には一定ですが、非constポインターを取得します。その非constポインターを使用してオブジェクトを変更することは非常に悪い考えです。

Cでは、「const制限」ポインターを持つことができます。つまり、ポイントされているオブジェクトは一時的に一定です。 「const restrict」ポインタがスコープ内にあるときにオブジェクトが何らかの方法で変更されると、未定義の動作が発生します。これは、constポインターよりも強力で、constポインターを介してオブジェクトを変更できないようにするだけです。

0
gnasher729