不変とconstの違い


28

私はよく用語immutableを見て、const同じ意味で使用しました。ただし、私の(小さな)経験から、この2つは、コードで作成する「契約」が大きく異なります。

Immutableは、このオブジェクトがまったく変更されないという契約を作成します(Pythonタプル、Java文字列など)。

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

明らかに、言語がシングルスレッド(PHP)であるか、線形または一意のタイピングシステム(Clean、Mercury、ATS)を持たない限り、2つは同等ではありません。

最初に、これら2つの概念の理解は正しいですか?

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


1
constすべての言語に存在するわけではなく、すべての言語に可変性と不変性が存在するわけではないので、この言語を作動的にすることは適用できません。これらの概念が適用される場合にのみ、言語固有です。

2
関連する推奨読書:種類の不変性(いくつかのC#の例ですが、大部分は言語に依存しません)。誰かがエリックリッパーにメダルを与えます。

回答:


14

この違いが最も重要なC ++についてお話します。

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

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

  2. 宣言されています const

  3. constメンバー関数は、メンバーconst_castを変更するためにconst修飾を削除するために使用しません

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

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

constC ++には、参照とポインターを修飾する別の機能もあります。const基準は、非を参照することができるconstオブジェクト。これは、使用する(一般的に必要または賢明ではないが)合法であるconst_castを通じてオブジェクトを変異させるconst、基準とする場合にのみ場合、そのオブジェクトを非宣言されています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.

19

キーワード「final」が「const」を表すJavaの場合、次のことを考慮してください。

final Person someone = new Person();

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

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


10

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

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

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

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

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

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


1
C ++のconstは不変オブジェクトを作成せず、アクセスレベルにすぎません。
クライム

「const double pi = 3.14」が不変ではないことを説明できますか?
メルトアカカヤ

まあそれはそれがどこにあるかに依存します。たとえば、「double * p_pi = const_cast <double *>(&pi); * p_pi = 42;」例えば。piがグローバルスペースまたはネームスペースにある場合、セグメンテーションエラーが発生しますが、特定のエラーではなく、未定義の動作です。piが実行時に利用可能な、静的ではないオブジェクトのメンバーである場合、pi == 42を取得します。 C ++で達成することはほとんど不可能です。あなたはそれを「シミュレート」することしかできません。constは不変ではありません。
クライム

1
@Klaimそのconstようなものを変更することは、IIRCがどこに割り当てられていても未定義の動作です。また、未定義の動作は、発生が保証されている特定のエラーよりも悪化します。これは、C ++を使用しないことを意味します-C ++はconst値を変更する手段を提供しません(mutableもちろんメンバーを除きますが、それはあなたのポイントではありません)。したがって、C ++に関する限り、それを行うことはできません。特定の実装が許可することはまったく別の問題です(最適化を使用してコンパイルする場合、プルしたスタントはpi置換されているため、使用した後の式には影響しません)。

「C ++の定数は不変オブジェクトを作成しない」は、あなた自身の答えで述べたようにグローバル定数を作成するため、依然として間違っています。このキーワードは、あるレベルではもちろんセマンティックです。そうでない場合、未定義の動作を使用したい場合でも、常にメモリセルの電圧を手動で変更し、不変オブジェクトの値を変更できます。
メルトアカカヤ

8

最初に、これら2つの概念の理解は正しいですか?

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

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

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

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

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

最終的に、まったく同じ保証を提供しないため、まったく同じではありません。


3

JavaScriptといえば、キーワードconstObject.freeze

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

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


0

C ++では同じです。ただし、constオブジェクトがメモリ内の場所にあり、OSがそのメモリに書き込む許可を持っている場合は、オブジェクトを変更できます。


1
実際には、それらは同じあるということに対する議論です。C++には、不変のキーワードや言語サポートがありません。また、プログラマーが言語を健全な方法で利用していると想定しています。それ以外の場合、constもまったく価値がありません。
K.ステフ

1
@ K.Steff -おそらくより良い余分な不変ネスがCに存在しないと言うために++のconstによって提供されるよりも、他の
マーティンベケット

絶対に正確です:)
K.ステフ

C ++ではまったく同じではありません。constは「読み取り専用」アクセスレベルであり、データが不変であることを意味するものではありません。ほとんどの場合、C ++でバイパスできます。
クライム

0

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

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

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

Cでは、「Hello」などの文字列リテラルを使用すると、5つの文字と後続のゼロバイトは実際には一定ですが、const以外のポインターを取得します。その非constポインターを使用してオブジェクトを変更することは非常に悪い考えです。

Cでは、「const restrict」ポインターを使用できます。これは、指しているオブジェクトが一時的に一定であることを意味します。「const restrict」ポインターがスコープ内にある間にオブジェクトが何らかの方法で変更された場合、未定義の動作が発生します。これはconstポインターよりも強力で、このポインターを使用してオブジェクトを変更することのみを防ぎます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.