2012-08-13 2 views
12

実用的な環境では、gccやMS Visual Studioを使って、同じサイズかintより小さい値型をconst参照で渡すのは悪いですか?C++では、const boolを参照渡しするのは悪いですか?

すなわち、このような関数を作成することが悪い:

void f(const bool& b); 

又は

void f(const char& c); 

なく:

void f(bool b); 

又は

void f(char c); 

私が尋ねる理由は、このような場合に参照を渡すことの利益は見られないが、何かが足りないことがあるということです。

+2

ほとんどの人が言っているように、これらの値を渡すことは恐らくより速いので、実際には何のポイントもありません。しかし、きれいなコードを書くことは、これらの小さな最適化の前に行われることに注意してください。時には、const参照で引数をとり、 'bool'と' char'のバージョンが一貫して見えるようにするために、非常にマイナーな点ですが、おそらく考慮する価値があるので、「なぜこれが違うのですか」と思っている人はいません。 – BoBTFish

答えて

15

これはわずかに悪いか、まったく効果がない可能性があります(元の値の格納場所、オプティマイザの良さ、それはあなたのコードを扱うことにします)。

標準では参照の実装方法は規定されていませんが、実際にはコンパイラはポインタを使用して参照を実装します。したがって、一般的なケースではbool&bool*を使用して実装されます。つまり、boolにアクセスするたびに、逆参照が必要になります。 boolはポインタより大きくないので、この欠点を相殺するために、メモリフットプリントの削減やバイトコピーの削減はありません。

結果として、より効率的であるため、受け入れられたプラクティスは値の周りにプリミティブを渡すことです。もちろん、参照を渡すことは実際には何も吹き飛ばすことはありませんが、ループ内の値にアクセスしない限り、おそらく測定可能な差は生じません。

+0

"ブールがポインタより大きくないので、この欠点を相殺するためにメモリフットプリントを減らしたり、バイトコピーを減らしたりすることはありません"と書くと、実際に複数のブールを渡した場合、参照によって渡されることによって実際に使用されるより多くのメモリをもたらすか、または関数の引数としてintと同じ領域を取るブールですか? – BlueTrin

+0

参照で渡されたプリミティブ型(例: 'bool const&')が見つかる可能性が高いのは、テンプレートのインスタンス化です。すべてのプリミティブ型を明示的に特化しない限り、プリミティブ型とより複雑な型は同じシグネチャを使用します。 –

+4

@BlueTrin:どのくらいのスペースが取られるかは、アーキテクチャ内の 'sizeof(bool)'と 'sizeof(bool *) 'の値によって決まります。各パラメータの倍数を渡しても画像は変わりません。 – Jon

-1

本当に重要ではありませんが、値渡しはより洗練されたコードとなり、したがって良い習慣とみなされます。

1

by valueではなく、const referenceという組み込み型を渡す方がはるかに速いので、それは良い方法だと思います。参照渡しの場合は、参照を作成(つまり住所を取る)した後、変数を使用する際に逆参照する必要があります。ほとんどの場合、どのような場合でもコンパイラによって最適化されます。

+1

関数がインライン化されている場合にのみ最適化できます。 *インライン関数*ほとんどの場合*を考慮するかどうかは異なる質問です。 –

2

値が一定であることを他のプログラマに伝えたいという理由の1つは、const boolで十分ですが、場合によってはより明確になることがあります。

+2

値を渡すと、関数が呼び出し元の値を変更しないことがさらに明確になります。 –

+0

const参照による受け渡しは、ソースが定数であるという意味を伝えません。関数によって変更されないということだけを伝えます(Björnの答え:関数外のコードは値を変更することができます)。さらに、 'const bool'を引数として使用すると、関数宣言でトップのcv-qualifierが削除されます(つまり' void f(bool); 'と' void f(const bool) 'は全く同じ関数宣言 –

0

理論的には、参照は通常ポインターを使用して実装されるため、良い考えではありません。それにもかかわらず、すべての合理的なコンパイラは、基本型のby-const-referenceとby-valueの間のセマンティクスにおける無関心を認識するのに十分なほどスマートでなければなりません。

複雑な型や基本型で動作する必要があり、過度の特殊化のオーバーヘッド(単純な例:std::vector)を必要としない、ある種のテンプレートインターフェイスがある場合は、選択肢がないことがよくあります。しかし、選択肢がある場合は、値ごとに基本型を渡すことをお勧めします。

11

パフォーマンスは別として、実際には異なる動作をする場合があります。

たとえば、constの参照を渡すと、関数は参照された変数の値を変更できないことを確認しますが、別のスレッドがそのようにする可能性があります。参照渡しの場合(constでさえ)、これらの変更が表示されますが、値渡しの場合は表示されません。

また、インターフェイスの定義によって、関数内の変数でできることが制限されます。

int foo(int a) { 
    a = 5; // valid 
} 

int bar(const int& a) { 
    a = 5; // compiler-error 
} 

参照渡しで、ローカルで使用するために変数の値を変更する場合は、余分なコピーを作成する必要があります。あなたが価値を渡すなら、あなたはすでにコピーを持っています。

+0

マルチスレッド環境についての非常に良い点 – BlueTrin

+4

参照変数を変更するために複数のスレッドを必要としないことに注意してください(たとえば、bool b(false); void f(const bool& – Mankarse

+1

+1(別の参照を介して)異なる場所での引数の可能な変更について言及するために、以下のものがあります。また、エイリアシングの問題のために最適化が行われないことを意味します。 –

関連する問題