web-dev-qa-db-ja.com

関数引数でconstおよびconst参照を使用する場合

引数が渡されるC++関数を作成するとき、オブジェクトが変更されないことを保証できる場合は常にconstを使用する必要があります。ポインターが変更されない場合はconstポインターを使用する必要があります。

他にこのプラクティスが助言されるのはいつですか?

いつconst参照を使用しますか?たとえば、ポインターを介して渡すだけの場合の利点は何ですか?

これについてはどうですかvoid MyObject::Somefunc(const std::string& mystring)文字列が実際にすでに不変オブジェクトである場合、const文字列を持つことのポイントは何でしょうか?

23
Tony The Lion

Constを追加するかどうかを尋ねるのは間違った質問です残念です。

非const参照を非constポインターを渡すことと比較する

_void modifies(T &param);
void modifies(T *param);
_

このケースは主にスタイルに関するものです。呼び出しをcall(obj)またはcall(&obj)のようにしたいですか?ただし、違いが重要な点が2つあります。 nullを渡せるようにするには、ポインタを使用する必要があります。また、演算子をオーバーロードしている場合は、代わりにポインターを使用できません。

Const refを値で比較する

_void doesnt_modify(T const &param);
void doesnt_modify(T param);
_

これは興味深いケースです。経験則では、「安価なコピー」タイプは値で渡されます。これらは一般に小さいタイプですが(常にではない)、他のタイプはconst refで渡されます。ただし、関数内でコピーを作成する必要がある場合は、 値で渡す必要があります です。 (はい、これは実装の詳細を公開します。C'est le C++。

Constポインターを非変更およびオーバーロードと比較します

_void optional(T const *param=0);
// vs
void optional();
void optional(T const &param); // or optional(T param)
_

これは、パラメーターの引き渡しがオプションであることを除いて、上記の非変更のケースに関連しています。ここでは、3つの状況すべての違いが最も小さいため、人生を最も簡単にするものを選択してください。もちろん、非constポインタのデフォルト値はあなた次第です。

値による定数は実装の詳細です

_void f(T);
void f(T const);
_

これらの宣言は実際にはまったく同じ関数です!値で渡す場合、constは純粋に実装の詳細です。 実際に試す:

_void f(int);
void f(int const) {/*implements above function, not an overload*/}

typedef void C(int const);
typedef void NC(int);
NC *nc = &f;  // nc is a function pointer
C *c = nc;  // C and NC are identical types
_
41
Roger Pate

一般的なルールは、可能な限りconstを使用し、必要な場合にのみ省略します。 constを使用すると、コンパイラーが最適化され、コードがどのように使用されるかをピアが理解できるようになります(コンパイラーは誤用の可能性をキャッチします)。

あなたの例と同様に、C++では文字列は不変ではありません。文字列への非const参照を関数に渡すと、関数がそれを変更する場合があります。 C++には不変性の概念が言語に組み込まれておらず、カプセル化とconstを使用してのみエミュレートすることができます(ただし、決して防弾にはなりません)。

@Eamonsのコメントを読み、いくつかのことを読んだ後、最適化がconstを使用する主な理由ではないことに同意します。主な理由は、正しいコードを持つことです。

4
Björn Pollex

質問はいくつかの誤った仮定に基づいているため、あまり意味がありません。

std::stringは、不変の文字列値をモデル化しません。変更可能な値をモデル化します。

「const参照」のようなものはありません。 constオブジェクトへの参照があります。区別は微妙ですが重要です。

関数引数のトップレベルのconstは、関数の実装でのみ意味があり、純粋な宣言では意味がありません(コンパイラーによって無視されます)。発信者には何も伝えません。これは実装の制限にすぎません。例えば。 int constは、関数の純粋な宣言の引数型としてはほとんど意味がありません。ただし、std::string const&constは最上位ではありません。

constへの参照渡しにより、データの非効率的なコピーを回避できます。一般に、データを関数に渡す引数の場合、値で小さい項目(intなど)を渡し、constを参照して大きい項目を渡す可能性があります。マシンコードでは、constへの参照を最適化するか、ポインタとして実装することができます。たとえば、32ビットのWindowsでは、intは4バイトで、ポインタは4バイトです。したがって、引数の型int const&はデータのコピーを削減しませんが、単純なコンパイラを使用すると、追加の間接参照が導入される可能性があります。

乾杯&hth。、

Constポインターに対するconst参照の主な利点は次のとおりです。パラメーターが必須であり、NULLにできないことは明らかです。逆に、私がconstポインターを見つけた場合、それが参照ではない理由はパラメーターがNULLである可能性があるということです。

0
Adesit