それでは、できるだけ頻繁にconstを使用することが常に推奨されるのはなぜですか? constを使用することは、C++のヘルプよりも苦痛のように思えます。しかし、もう一度、私はpythonの観点からこれに来ています:何かを変更したくない場合、それを変更しないでください。質問:
Constとしてマークするたびにエラーが発生し、どこか他の関数もconstに変更する必要があるようです。次に、これによりanother functionを別の場所に変更する必要があります。これは経験を積むだけで簡単になりますか?
Const reallyを使用する利点は、問題を補うのに十分ですか?オブジェクトを変更するつもりがない場合、それを変更しないコードを作成しないのはなぜですか?
この時点で、正確性と保守性の目的でconstを使用する利点に最も焦点を当てていることに注意する必要がありますが、パフォーマンスへの影響を理解することも良いことです。
これは「定数の正確性」に関する決定的な記事です。 https://isocpp.org/wiki/faq/const-correctness 。
一言で言えば、constを使用するのは良い習慣です...
コンパイラはそれを最適化できます。たとえば、あなたはから保護されています
if( x = y ) // whoops, meant if( x == y )
同時に、コンパイラは、変数/関数の状態が常に正確にわかるため、より効率的なコードを生成できます。タイトなC++コードを書いている場合、これは良いことです。
Const-correctnessを一貫して使用するのは難しい可能性があるという点では正しいですが、終了コードはより簡潔で安全にプログラムできます。多くのC++開発を行うと、この利点がすぐに現れます。
以下に、constの正確性によってユーザーを保護できる一般的なエラーのあるコードを示します。
void foo(const int DEFCON)
{
if (DEFCON = 1) //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
{
fire_missiles();
}
}
Constとしてマークするたびにエラーが発生し、どこか他の関数もconstに変更する必要があるようです。次に、これにより、別の場所で別の関数を変更する必要があります。これは経験を積むだけで簡単になりますか?
経験から、これは完全な神話です。それは、const-correctコードがconst-correctコードと一緒に座っているときに起こります。最初からconst-correctを設計する場合、これは決して問題になりません。 constを作成し、その後、他の何かがコンパイルされない場合、コンパイラは非常に重要なことを通知しているため、時間をかけて修正する必要があります適切に。
最初にコードを書いているときは、あなたのためではありません。クラスまたはインターフェイス内のメソッド宣言を見て、それが何をするのかを見る他の誰か(または数か月後)のためです。オブジェクトを変更しないことは、そこから収集する重要な情報です。
Constを厳密に使用すると、ほとんどの関数に実際の変数がほとんどないことに驚くでしょう。多くの場合、ループカウンターにすぎません。コードがそのポイントに達した場合、内部で温かい気持ちになります...コンパイルによる検証...関数型プログラミングの領域が近くにあります...今、ほとんどそれに触れることができます...
constは、開発者として作成する約束であり、コンパイラーの支援を強制することです。
Constが正しい理由:
ConstなしでC++をプログラミングすることは、安全ベルトなしで運転することに似ています。
車に乗るたびに安全ベルトを装着するのは苦痛であり、365日のうち364日は安全に到着します。
唯一の違いは、車に問題が発生するとすぐに感じることです。一方、constを使用しないプログラミングでは、クラッシュを引き起こした原因を2週間検索しなければならない場合があります。効率のために非const参照で渡されました。
私の哲学は、コンパイル時のチェックでちょっとぴかぴかした言語を使用するなら、それを最大限に活用するということです。 const
は、コンパイラーが強制的に通信する方法ですmean ...コメントやdoxygenよりも優れていますなるでしょう。あなたは代価を払っている、価値を引き出してみませんか?
組み込みプログラミングの場合、グローバルデータ構造を宣言するときにconst
を慎重に使用すると、定数データをRAMに配置することにより、多くのROMを節約できます=またはRAMにブート時にコピーせずにフラッシュします。
日常のプログラミングでは、const
を慎重に使用すると、文字列リテラルやその他の定数グローバルデータを変更しようとするため、クラッシュしたり予期せず動作したりするプログラムの作成を避けることができます。
大規模プロジェクトで他のプログラマーと作業する場合、const
を適切に使用すると、他のプログラマーがあなたを絞るのを防ぐのに役立ちます。
constの正確性は、最初から本当に必要なものの1つです。あなたが見つけたように、特に追加しようとしている新しい関数と、すでに存在する古い非正確でない関数との間に多くの依存関係がある場合、後で追加するのは大きな苦痛です。
私が書いた多くのコードでは、コンポジションを多く使用する傾向があるため、実際に努力する価値がありました。
class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };
Const-correctnessがなければ、クラスBの内部状態を操作する人がいないことを保証するために、値によって複雑なオブジェクトを返すことに頼らなければなりません。
つまり、const-correctnessは、将来の痛みから身を守るための防御的なプログラミングメカニズムです。
const
を使用すると、背後で「物事を変更する」コードを分離できます。したがって、クラスでは、オブジェクトの状態を変更しないすべてのメソッドをconst
としてマークします。つまり、そのクラスのconst
インスタンスは、_const
以外のメソッドを呼び出すことができなくなります。これにより、オブジェクトを変更する可能性のある機能を誤って呼び出すことを防ぎます。
また、const
はオーバーロードメカニズムの一部であるため、シグネチャが同じ2つのメソッドを使用できますが、1つはconst
を使用し、もう1つは使用しません。 const
を含む参照はconst
参照に対して呼び出され、もう1つはconst
参照以外について呼び出されます。
例:
#include <iostream>
class HelloWorld {
bool hw_called;
public:
HelloWorld() : hw_called(false) {}
void hw() const {
std::cout << "Hello, world! (const)\n";
// hw_called = true; <-- not allowed
}
void hw() {
std::cout << "Hello, world! (non-const)\n";
hw_called = true;
}
};
int
main()
{
HelloWorld hw;
HelloWorld* phw1(&hw);
HelloWorld const* phw2(&hw);
hw.hw(); // calls non-const version
phw1->hw(); // calls non-const version
phw2->hw(); // calls const version
return 0;
}
Pythonに変数があるとします。あなたは想定を変更するわけではないことを知っています。誤って行った場合はどうなりますか?
C++を使用すると、そもそもできるはずのないことを誤って実行することから身を守ることができます。技術的にはとにかく回避できますが、自分で撮影するには余分な作業が必要です。
ニースの記事があります ここ c ++のconstについて。それは非常に単純明快な意見ですが、それが一部を助けることを願っています。
「const」キーワードを使用する場合、クラスへの別のインターフェースを指定しています。すべてのメソッドを含むインターフェイスと、constメソッドのみを含むインターフェイスがあります。これにより、変更したくないものへのアクセスを制限できます。
はい、時間とともに簡単になります。
理論的にはconstの正確さが好きです。実際に厳密に適用しようとするたびに、最終的に壊れてしまい、const_castはコードをcodeくし始めます。
多分それは私が使っているデザインパターンだけなのかもしれませんが、constは常にブラシが広すぎます。
たとえば、単純なデータベースエンジンを想像してください。スキーマオブジェクト、テーブル、フィールドなどがあります。ユーザーは、テーブルスキーマ自体を変更することを許可されていないことを意味する 'const Table'ポインターを持っています。テーブルに関連付けられたデータ? Insert()メソッドがconstとマークされている場合、内部的にconst-nessをキャストして、実際にデータベースを操作する必要があります。 constとしてマークされていない場合、AddFieldメソッドの呼び出しに対して保護されません。
答えは、定数要件に基づいてクラスを分割することかもしれませんが、それは、それがもたらす利益のために私が望んでいるよりも設計を複雑にする傾向があります。
Constを使用してコンパイラのヒントを提供することもできます。次のコードに従って
#include <string>
void f(const std::string& s)
{
}
void x( std::string& x)
{
}
void main()
{
f("blah");
x("blah"); // won't compile...
}