45

免責事項: const-correctness の有用性について 2 つの質問があることは承知していますが、他のプログラミング言語とは対照的に、C++ で const-correctness がどのように必要であるかについては誰も議論していません。また、これらの質問に対する回答に満足していません。

これまでにいくつかのプログラミング言語を使用してきましたが、C++ で気になる点の 1 つは、const-correctness の概念です。Java、C#、Python、Ruby、Visual Basic などにはそのような概念はありません。これは C++ に非常に固有のもののようです。

あなたが私に C++ FAQ Lite を紹介してくれる前に、私はそれを読みましたが、納得できません。完全に有効で信頼性の高いプログラムは常に Python で作成されており、const キーワードやそれに相当するものはありません。Java および C# では、オブジェクトを final (または const) と宣言できますが、const メンバー関数または const 関数パラメーターはありません。関数がオブジェクトを変更する必要がない場合は、オブジェクトへの読み取りアクセスのみを提供するインターフェイスを使用できます。この手法は、C++ でも同様に使用できます。私が取り組んだ 2 つの実際の C++ システムでは、どこでも const がほとんど使用されておらず、すべて正常に機能していました。したがって、const でコードベースを汚染することの有用性については、私は納得していません。

他のプログラミング言語とは対照的に、C++ で const が必要になるのは何でしょうか。

これまでのところ、const を使用する必要があるケースは 1 つだけ見てきました。

#include <iostream>

struct Vector2 {
    int X;
    int Y;
};

void display(/* const */ Vector2& vect) {
    std::cout << vect.X << " " << vect.Y << std::endl;
}

int main() {
    display(Vector2());
}

const をコメントアウトしてこれをコンパイルすると、Visual Studio で受け入れられますが、警告C4239が表示され、非標準の拡張機能が使用されます。したがって、一時的に渡し、コピーを避け、標準に準拠したままにするという構文の簡潔さが必要な場合は、const 参照で渡す必要があります。それでも、これは根本的な理由というよりは癖のようなものです。

それ以外の場合、const を使用する他のコードとインターフェイスする場合を除いて、const を使用する必要がある状況は実際にはありません。const は、私には、それが触れるすべてのものに広がる独善的な疫病に他なりません。

const が C++ で機能する理由は、それをキャストできるからです。それを捨てることができなければ、あなたの世界はつまらなくなるでしょう。const Bla を取るメソッドを宣言する場合、非 const Bla を渡すことができます。でも逆なら仕方ない。非 const Bla を取るメソッドを宣言する場合、const Bla を渡すことはできません。だから今、あなたは立ち往生しています。そのため、const ではないすべてのものの const バージョンが徐々に必要になり、最終的には影の世界になります。C++ では、このチェックが必要かどうかは純粋にオプションであるため、C++ では問題ありません。気に入らない場合は、constness を叩くことができます。

Anders Hejlsberg (C# アーキテクト)、CLR Design Choices

4

14 に答える 14

65

const の正確さは、私が考えることができる C++ に 2 つの注目すべき利点をもたらします。

  • 一連のインターフェイスを必要とせずに、可変/不変データの広範な概念を可能にします。const オブジェクトで実行できるかどうかについて、個々のメソッドに注釈を付けることができ、コンパイラはこれを強制します。はい、面倒な場合もありますが、一貫して使用し、使用しない場合const_castは、可変データと不変データに関してコンパイラーが安全性をチェックしています。
  • オブジェクトまたはデータ項目がconstの場合、コンパイラはそれを読み取り専用メモリに自由に配置できます。これは、組み込みシステムでは特に重要です。C++ はこれをサポートしています。他のほとんどの言語はそうではありません。これはまた、実際にはほとんどの環境でキャストできますが、一般的なケースでは安全にキャストできないことを意味しconstます。

const の正確性などを備えた言語は C++ だけではありません。OCaml と標準 ML は用語は異なりますが、同様の概念を持っています。ほとんどすべてのデータは不変 (const) であり、何かを可変にしたい場合は、別の型 (ref型) を使用してそれを実現します。したがって、近隣言語内の C++ に固有のものです。

最後に、別の方向に進みます。Java で const が必要になることが何度かありました。 final単純に不変のデータ (特に、可変データの不変のビュー) を作成するには不十分であり、インターフェイスを作成したくない場合があります。Java API での Unmodifiable コレクションのサポートと、const が有用である理由の例として、変更が許可されているかどうかを実行時にのみチェックするという事実を見てください (または、少なくともインターフェイス構造を深めて、List と MutableList を持たせる必要があります)。不変の構造体を変更しようとしても、コンパイル タイプのエラーにならないという理由にはなりません。

于 2009-09-02T21:06:20.430 に答える
32

const-correctness が「必要」であると主張する人はいないと思います。繰り返しになりますが、クラスも実際には必要ありませんね。名前空間、例外などについても同じことが言えます。

const-correctness は、コンパイル時にエラーをキャッチするのに役立ちます。これが有用な理由です。

于 2009-09-02T21:05:18.310 に答える
16

const は、何かを表現する方法です。それを表現することが重要だと考えれば、どんな言語でも役に立ちます。言語設計者が便利だと思わなかったため、この機能はありません。この機能があれば、同じくらい便利だと思います。

Javaのスロー仕様のようなものだと思います。それらが気に入ったら、おそらく他の言語でも気に入るはずです。しかし、他の言語の設計者は、それがそれほど重要だとは考えていませんでした。

于 2009-09-02T21:03:39.467 に答える
13

そうです、const-correctness は必要ありません。Java や Python の場合と同じように、すべてのコードを const キーワードなしで記述して機能させることができます。

しかし、そうすると、const 違反をチェックする際にコンパイラの助けが得られなくなります。コンパイラがコンパイル時に通知するエラーは、実行時にしか検出されないため、診断と修正に時間がかかります。

したがって、 const-correctness 機能を覆したり回避したりすることは、長期的には物事を難しくするだけです。

于 2009-09-02T21:06:14.593 に答える
8

プログラミングとは、最終的にコンピューターによって処理される言語で作成することですが、それは、コンピューターと同じプロジェクト内の他のプログラマーと通信する方法でもあります。言語を使用する場合、言語で表現できる概念に制限されます。 const は、問題と解決策を説明するために使用できるもう 1 つの概念です。

一貫性により、設計ボードからコードまで、他の言語にはない 1 つの概念を明確に表現できます。それを持たない言語から来たあなたは、一度も使ったことのない概念に困惑しているように見えるかもしれません。

言語と思考は密接に結びついています。自分が話す言語でしか自分の考えを表現できませんが、言語によって考え方も変わります。作業した言語に const キーワードがなかったという事実は、同じ問題に対する他の解決策を既に見つけていることを意味し、それらの解決策はあなたにとって自然に思えるものです。

質問では、オブジェクトの内容を変更する必要のない関数で使用できる非変更インターフェイスを提供できると主張しました。少し考えてみると、この同じ文は、なぜ const が扱いたい概念なのかを示しています。変化しないインターフェイスを定義してクラスに実装する必要があるのは、言語でその概念を表現できないという事実を回避するためです。

定数性により、コンパイラ (および他のプログラマ) が理解できる言語でこれらの概念を表現できます。受け取ったパラメーター、保存した参照をどうするかについて妥協を確立したり、クラスのユーザーが提供した参照を使ってできることの制限を定義したりしています。ほとんどの重要なクラスは、属性によって表される状態を持つことができ、多くの場合、保持する必要がある不変条件があります。この言語を使用すると、一部の内部データへのアクセスを提供する関数を定義できると同時に、読み取り専用ビューへのアクセスを制限して、外部コードが不変条件を壊さないことを保証できます。

これは、他の言語に移行するときに私がもっと恋しく思う概念です。とりわけ、外部コードから見える必要がある型 A の属性 a を持つクラス C があるシナリオを考えてみましょう (クラスのユーザーは、a に関するいくつかの情報を照会できる必要があります)。A の型に変更操作がある場合、ユーザー コードが内部状態を変更しないようにするには、 a のコピーを作成して返す必要があります。クラスのプログラマーは、コピーを実行する必要があり、(おそらく高価な) コピーを実行する必要があることを認識している必要があります。一方、言語で定数を表現できる場合は、オブジェクトへの定数参照 (実際にはオブジェクトの定数ビューへの参照) を返し、内部要素を返すだけで済みます。これにより、ユーザーコードは、非変更としてチェックされたオブジェクトの任意のメソッドを呼び出すことができます。

問題/利点は、すべてが視点に依存しますが、一定であることは、それがバイラルであることです。オブジェクトへの定数参照を提供する場合、変更不可としてフラグが設定されたメソッドのみを呼び出すことができ、どのメソッドにこのプロパティがあるかをコンパイラに通知する必要があります。メソッド定数を宣言すると、そのメソッドを呼び出すユーザー コードがオブジェクトの状態を保持することをコンパイラに伝えます。定数シグネチャを持つメソッドを定義 (実装) すると、コンパイラは約束を思い出させ、データを内部的に変更しないことを実際に要求します。

この言語を使用すると、他の方法では表現できないメソッドのコンパイラ プロパティを伝えることができます。同時に、コンパイラは、設計に準拠していない場合やデータを変更しようとした場合に通知します。

このコンテキストでは、 const_cast<> は決して使用しないでください。結果が未定義の動作の領域に入る可能性があるためです (言語の観点から: オブジェクトは読み取り専用メモリにある可能性があり、プログラムの観点から) : 他のクラスの不変条件を壊している可能性があります)。しかし、もちろん、C++FAQ lite を読んでおけば、すでにご存知でしょう。

補足として、Java の final キーワードは、(C++ 参照またはポインターで) 参照を扱う場合、C++ の const キーワードとはまったく関係ありません。final キーワードは、参照先のローカル変数 (基本型か参照かに関係なく) を変更しますが、参照先オブジェクトの修飾子ではありません。つまり、最終参照を介して変更メソッドを呼び出して、参照されるオブジェクトの状態を変更できます。C++ では、参照は常に定数であり (構築中にのみオブジェクト/変数にバインドできます)、const キーワードは、ユーザー コードが参照されたオブジェクトを処理する方法を変更します。(ポインターの場合、データムとポインターの両方に const キーワードを使用できます: X const * constは、定数 X への定数ポインターを宣言します)

于 2009-09-02T22:25:00.067 に答える
6

FLASH または ROM のデータを使用して組み込みデバイス用のプログラムを作成している場合、const-correctness なしでは生きられません。これにより、さまざまな種類のメモリ内のデータの正しい処理を制御できます。

于 2009-09-03T07:07:40.743 に答える
4

戻り値の最適化を利用するために、メソッドでも const を使用する必要があります。Scott Meyers のより効果的な C++ の項目 20 を参照してください。

于 2009-09-02T21:04:30.417 に答える
3

ハーブサッターからのこのトークとビデオは、スレッドセーフに関する の新しい意味を説明しています。const

恒常性は、以前はあまり心配しなければならなかったかもしれませんが、C ++ 11では、スレッドセーフなコードを記述したい場合は、との重要性を理解する必要がありますconstmutable

于 2013-01-18T10:33:19.113 に答える
2

Anders Hejlsberg(C#アーキテクト):...非const Blaを受け取るメソッドを宣言する場合、constBlaを渡すことはできません。だから今あなたは立ち往生しています。したがって、constではないものすべてのconstバージョンが徐々に必要になり、最終的にはシャドウワールドになります。

繰り返しになりますが、一部のメソッドで「const」を使用し始めた場合、通常、ほとんどのコードでこれを使用する必要があります。しかし、コードのconst-correctnessの維持(入力、一部のconstが欠落している場合の再コンパイルなど)に費やされる時間は、const-correctnessをまったく使用しないことによって発生する可能性のある(非常にまれな)問題の修正よりも長いようです。したがって、最新の言語(Java、C#、Goなど)でconst-correctnessがサポートされていない場合、同じコード品質の開発時間がわずかに短縮される可能性があります。

constの正当性を実装するための拡張リクエストチケットは1999年からJavaCommunityProcessに存在していましたが、上記の「const汚染」と互換性の理由により、2005年にクローズされました:http://bugs.sun.com/bugdatabase/view_bug.do ?bug_id = 4211070

C#言語には定数の正当性構造はありませんが、[Pure]および[Immutable]属性を使用して.NET Frameworkの「MicrosoftCodeContracts」(ライブラリ+静的分析ツール)に同様の機能がまもなく登場する可能性があります:C#の純粋関数

于 2013-01-17T16:16:46.567 に答える
2

実際、そうではありません...とにかく、完全ではありません。

他の言語、特に Haskell、D、Rust、Scala などの関数型言語またはハイブリッド言語では、可変性の概念があります。変数は可変または不変であり、通常はデフォルトで不変です。

これにより、あなた (およびあなたのコンパイラ/インタープリター) は関数についてより適切に推論できます: 関数が不変の引数しかとらないことがわかっている場合、その関数は変数を変更してバグを引き起こしているものではないことがわかります。

C と C++ は const を使用して似たようなことを行いますが、保証がはるかに緩い点が異なります。不変性は強制されません。コール スタックのさらに下にある関数は constness をキャストし、データを変更する可能性がありますが、それは API コントラクトの意図的な違反になります。したがって、意図またはベスト プラクティスは、他の言語の不変性とまったく同じように機能することです。

そうは言っても、C++ 11 には、より制限された const キーワードと並んで、実際の変更可能なキーワードが含まれるようになりました。

于 2014-04-18T23:09:57.297 に答える
2

C、Java、および C# では、渡されたオブジェクトを関数で変更できるかどうかは、呼び出しサイトを見ることでわかります。

  • Javaでは、それが間違いなく可能であることを知っています。
  • Cでは、「&」または同等のものがある場合にのみ可能であることがわかっています。
  • C# では、呼び出しサイトでも「ref」と言う必要があります。

非 const 参照呼び出しは値渡しと同じように見えるため、一般に C++ ではこれを伝えることはできません。const 参照を使用すると、C 規則を設定して適用できます。

これにより、関数を呼び出すコードの可読性が大幅に向上します。これはおそらく、言語機能を正当化するのに十分です。

于 2009-09-02T21:19:05.553 に答える
1

C++ の const キーワード (パラメーターと型宣言に適用される) は、プログラマーが足の親指を撃ち落とし、その過程で足全体を取り出すのを防ぐための試みです。

基本的な考え方は、何かを「変更できない」とラベル付けすることです。const 型は変更できません (デフォルト)。const ポインターは、メモリ内の新しい場所を指すことはできません。シンプルですね。

ここで、const の正確性の出番です。const を使用するときに考えられる組み合わせのいくつかを次に示します。

const 変数 は、変数名でラベル付けされたデータを変更できないことを意味します。

const 変数への ポインターは、ポインターを変更できることを意味しますが、データ自体は変更できません。

変数への const ポインタは、 (新しいメモリ位置を指すように) ポインタを変更することはできませんが、ポインタが指すデータは変更できることを意味します。

const 変数への const ポインターは 、ポインターもポインターが指すデータも変更できないことを意味します。

いくつかのことがいかに間抜けであるかがわかりますか?そのため、const を使用するときは、どの const にラベルを付けるかを正しく指定することが重要です。

ポイントは、これは単なるコンパイル時のハックだということです。ラベル付けは、命令を解釈する方法をコンパイラに伝えるだけです。const からキャストすると、やりたいことが何でもできます。ただし、適切にキャストされた型で const 要件を持つメソッドを呼び出す必要があります。

于 2009-09-02T21:02:27.037 に答える
0

たとえば、次の関数があります。

void const_print(const char* str)
{
    cout << str << endl;
}

別の方法

void print(char* str)
{
    cout << str << endl;
}

主に:

int main(int argc, char **argv)
{
    const_print("Hello");
    print("Hello");        // syntax error
}

これは、"hello" が const char ポインターであるため、(C スタイルの) 文字列は読み取り専用メモリに格納されます。しかし、プログラマーが値が変更されないことを知っている場合、これは全体的に役立ちます。したがって、セグメンテーション違反の代わりにコンパイラ エラーを取得します。不要な割り当てのように:

const int a;
int b;
if(a=b) {;} //for mistake

左オペランドは const int なので。

于 2012-02-16T23:33:44.720 に答える