特に明記しない限り、C ++のすべてのオブジェクトは変更可能ですか?


8

特に明記しない限り、C ++のすべてのオブジェクトは変更可能ですか?

PythonとJavaScriptでは、文字列、タプル、ユニコードを変更できません。C ++に不変なものがあるかどうか、またはすべてのオブジェクトが変更可能であるかどうかを疑問に思っていましたconst。不変にするために型修飾子を使用する必要があります。


2
「デフォルト」とはどういう意味ですか?
BЈовић

別の言い方をしない限り、C ++のすべてのオブジェクトは変更可能です。
GMの

1
はい、そうです。これは「可変」キーワードと同じではないことに注意してください。
Olav

3
質問の本文の質問は、タイトルの質問とは異なりますか?
user253751 2017年

@immibisそれはほんの少しのコンテストを追加するだけでした
GM

回答:


18

不変性は以前からよく理解されてきました。Python、Java、およびC ++には、直接比較を困難にする異なるメモリモデルがあります。最初に引用した記事の著者は、C ++を知らないようです。

Python、Java、およびほとんどのマルチパラダイム言語と同様に、CおよびC ++はデフォルトで可変性を許可します。これは、プログラマーが通常望んでいることです。String x変数がある場合、新しい値を割り当てられるようにしたいのですx = "foo"

CおよびC ++のconstシステムは、Python、Java、さらにはScalaに欠けている多くの微妙な不変性を可能にします。C ++関数がa const std::string&またはaを取る場合、const char*この関数はその文字列の内容を変更しない(できない)ことを約束します(そしてコンパイラはある程度保証します)。constオブジェクトを指定すると、constとしてマークされているそのオブジェクトのメソッドのみを呼び出すことができます。C ++クラスのパブリックメンバーがのみの場合const、オブジェクトは事実上不変です。

ただし、CおよびC ++のオブジェクトはメモリロケーションであり、変数はメモリロケーションの名前であるため、これは混乱を招くことがあります。対照的に、PythonおよびJavaの変数は、オブジェクトへのポインターの名前です。参照セマンティクスを持つ言語でx = yは、「xがyと同じオブジェクトを指すようにする」ことを意味します。ポインターをコピーするだけなので、これは不変オブジェクトで可能です。C ++のような値のセマンティクスを持つ言語では、それは「の内容を更新する意味xの内容がy」。したがって、CまたはC ++で変数の再割り当てが必要な場合は、変数にconst型がない可能性があります。不変オブジェクトでこれを行うには、明示的にポインターを使用する必要があります。

JavaとPythonが不変の文字列オブジェクトを使用することは基本的な設計上の決定ですが、マルチスレッド環境での不変性の利点とは直接関係していません。1つの理由は、ソースコードの文字列リテラルをプールできるため、オブジェクトの数が減ることです。これはC / C ++でも可能です。C ++では、リテラル"foo"に型がありますconst char[4](4番目の文字が終了文字です'\0')。もう1つの理由は、dicts / mapのセットおよびキーのエントリは変更してはならないことです。文字列はdictキーとして広く使用されているため(ほとんどのPythonオブジェクトはdictです)、不変性により一般的なエラーの原因が取り除かれます。Javaでは、不変文字列のもう1つの理由はJavaセキュリティモデルです。これらの理由はすべて、マルチスレッドとはまったく無関係です。

Javaが不変性を念頭に置いて構築されている場合、言語の外観は大きく異なります。それはC ++に密接に影響を受けていますが、デザイナーはより単純な言語を作成するために一生懸命努力しました。constを取り除くことはそのようなステップの1つです。C ++のconst参照と同等のJavaのものは、任意の変更メソッドをとして実装しthrows new NotImplementedException()、非変更メソッド呼び出しを実際のコレクションに転送するアダプターまたはデコレーターです。java.utilコレクションインターフェースがすべて可変性を暗示しているという事実は、不変第一言語を目指して努力しなかった明確な兆候です。

Javaが並行性の問題を解決するために提唱したソリューションは、不変性ではなく、広範なロックでした。すべてのオブジェクトには、synchronizedブロックまたはメソッド全体で使用できるミューテックスが含まれています。結局のところ、これはパフォーマンスに適しておらず、十分にスケーリングされず、エラーが発生しやすく、変更可能なグローバル状態に対処する必要があります。


13
これはプログラマーが通常望んでいることです =>それはかなり論争の的になっている主張です。私の経験は実際には逆です。ほとんどのローカル変数は不変で、時々可変です。Rustなどの言語(可変性にはmutキーワードが必要であり、不必要な可変性がコンパイラーによってフラグが立てられる場合)は、私の仮説をサポートする傾向があります。Rustには、letバインドよりも多くのバインディングがありますlet mut
Matthieu M.17年

1
@MatthieuM .:部分的にfor x in 1..10let mut、がループ変数の定義に使用していないためですが、明らかに(ループレベルのみで、ループ本体内ではなく)可変性が必要です。
MSalters 2017年

@MSalters:もちろんですが、C ++にもrange-for構文があります:)
Matthieu M.

4
@MSalters私は、xと呼ばれる10個の変数を、10個の値ではなく、10個の値にバインドすることを特徴としています
Caleth

1
@MatthieuM。不変性は良いことだと私は同意しますが、C ++では、それが常にオプションであるとは限らないか、少なくとも過度に扱いにくいものです。たとえば、複数のステップでconst変数を初期化するには、そのオブジェクトがまだconstでない別の関数でそれを行う必要があります。少なくともC ++ 11ではconst T o = [&]{T o; o.init(...); return o;}();、不変性を念頭に置いて設計されていないAPIについて、すぐに呼び出されるラムダを使用しましょう。
アモン

9

ほとんど。言語自体はconst、を使用しない限りすべてを可変として扱います、単に変更する方法を提供しないだけで、コンパイラに不変であると通知せずに不変オブジェクトを構築することは可能です。

たとえば、次のクラスを見てください。

class MyClass {
    int value;
public:

    MyClass(int v) : value(v) {}
    int getValue() {return value;}

    MyClass &operator=(const MyClass &other) = delete;
};

のインスタンスMyClassは不変です。なぜなら、それらを変更する方法がないからです。しかし、コード内のどこにも、それらが不変であると実際に記述されていません。(これは、JavaのStringクラスのインスタンスが不変であるのと同じ方法です)


(私は錆びてきています)deleteここでコピー代入演算子を使用すると、移動代入演算を介して右辺値参照から代入できないことも保証されますか?
underscore_d 2017年

そして、明示的なデストラクタ呼び出しでオブジェクトを破棄し、配置を新しい数に変更して再作成しますか?
Peter Green

1
@underscore_d移動割り当てを暗黙的に追加しないために、オペレーターをユーザー定義としてカウントします、はい
Caleth

特定のクラスのオブジェクトが常に不変であることをコンパイラーに知らせるメカニズムが、より良い最適化につながるのではないかと思います。たとえば、キャッシュされたオブジェクトを更新する必要はありません。この特定の例(および一般にこのパターンに従うクラス)では、const valueを宣言しgetValue()、const関数を宣言すると役立つでしょう。
ピーター-モニカを2017年

1
@PeterGreenいいえ、それはオブジェクトを破棄して新しいオブジェクトを作成するものとして数えられます。
user253751 2017年

2

いいえ、例外が1つあります。ラムダと、拡張機能によってキャプチャされるオブジェクトは、デフォルトでは不変です。

int i = 0;

[i]{//capturing the value i
    i++; //does not compile, i is const
};

[i]() mutable{ //make the lambda mutable
    i++; //compiles fine
};

したがってconst、不変にするために追加する代わりに、不変にmutableするために追加しますconst

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