0

「いつ参照を使用し、いつポインターを使用するのですか?」について多くの質問があります。彼らは私を少し混乱させました。参照は単なるアドレスなので、メモリを必要としないと思いました。

今、私は簡単なDateクラスを作り、彼らにコードレビューのコミュニティを見せました. 次の例では参照を使用しないように言われました。しかし、なぜ?
誰かが、ポインターが割り当てるのと同じメモリを割り当てると私に言いました。それは私が学んだことの反対です。

class A{
int a;
public:
   void setA(const int& b) { a = b; } /* Bad! - But why?*/
};

class B{
int b;
public:
   void setB(int c) { b = c; } /* They told me to do this */
};

では、引数で参照やポインタを使用するのはいつで、単純なコピーだけを使用するのはいつですか? 私の例の参照がなければ、定数は不要ですか?

4

5 に答える 5

8

悪いことを保証するものではありません。ただし、この特定のケースでは不要です。

多くの (またはほとんどの) コンテキストでは、参照は変装したポインターとして実装されます。あなたの例はたまたまそれらのケースの1つです。関数がインライン化されないと仮定すると、パラメーターbは「内部で」ポインターとして実装されます。setAしたがって、最初のバージョンで実際に渡すのは へのポインタint、つまり引数値への間接アクセスを提供するものです。2 番目のバージョンでは、immediate を渡します。intつまり、引数値への直接アクセスを提供するものです。

どちらが優れていて、どちらが劣っていますか? 多くの場合、ポインターは よりもサイズが大きいためint、最初のバリアントがより多くのデータを渡す可能性があります。これは「悪い」と見なされるかもしれませんが、通常、両方のデータ型がハードウェアのワード サイズに収まるため、特にパラメータが CPU レジスタで渡される場合は、おそらく大きな違いはありません。

また、関数内を読み取るbには、その偽装ポインターを逆参照する必要があります。これは、パフォーマンスの観点からも「悪い」ことです。

これらは、小さなサイズ (ポインタ サイズ以下) のパラメータを値で渡すことを好む正式な理由です。パラメーターまたはより大きなサイズの場合、const 参照で渡す方が適切です (明示的にコピーを必要としない場合)。

ただし、ほとんどの場合、単純な関数はおそらくインライン化されるため、使用するパラメーターの型に関係なく、2 つのバリアントの違いが完全になくなります。


const2 番目のバリアントで不要であるという問題は、別の話です。最初のバリアントでconstは、2 つの重要な目的を果たします。

1) パラメータ値を変更できないようにするため、実際の引数が変更されないように保護します。参照が でなかった場合はconst、参照パラメーターを変更して、引数を変更することができます。

2) call のように、右辺値を引数として使用できますsome_obj.setA(5)。それがなければ、そのconstような呼び出しは不可能です。

2 番目のバージョンでは、これはどちらも問題ではありません。パラメータはその引数のローカルコピーであるため、実際の引数を変更から保護する必要はありません。パラメータに何をしても、実際の引数は変更されません。SetAまた、パラメーターが宣言されているかどうかに関係なく、既に右辺値を引数として使用できますconst

このため、人々は通常const、値によって渡されるパラメーターにトップレベルの修飾子を使用しません。ただし、それを宣言すると、関数内constのローカルを変更できなくなりbます。適度に人気のある「元のパラメーター値を変更しない」という規則を強制するため、実際にそれを好む人もいます。そのためconst、パラメーター宣言でトップレベルの修飾子が使用されていることがあります。

于 2013-07-12T16:08:50.123 に答える
4

intまたはのような軽量型longを使用する場合は、値渡しを使用する必要があります。これは、参照の処理による追加コストが発生しないためです。ただし、重い型を渡す場合は、参照を使用する必要があります

于 2013-07-12T16:08:59.670 に答える
0

参照はポインターとして実装されます (これは必須ではありませんが、普遍的に当てはまると思います)。

したがって、最初のものでは、「int」を渡すだけなので、そのintへのポインターを渡すと、渡すのにほぼ同じ量のスペースが必要になります(アーキテクチャに応じて、同じまたはそれ以上のレジスタ、または同じまたはそれ以上のスタックスペース) )、したがって、そこには節約はありません。さらに、そのポインターを逆参照する必要がありますが、これは追加の操作です (そして、アーキテクチャによっては、2 番目のポインターを使用する必要がない可能性があるため、ほぼ確実にメモリにアクセスする必要があります)。

ここで、渡しているものが int よりもはるかに大きい場合は、ポインターのみを渡しているため、最初のものの方が優れている可能性があります。[非常に大きなオブジェクトであっても、値渡しが理にかなっている場合があることに注意してください。これらのケースは通常、とにかく独自のコピーを作成することを計画している場合です。その場合、全体的なアプローチによって最適化能力が向上する可能性があるため、コンパイラーにコピーを行わせることをお勧めします。これらのケースは非常に複雑です。私の意見では、この質問をしている場合は、それらに取り組む前に C++ をもっと勉強する必要があります。興味深い読み物にはなりますが。]

于 2013-07-12T16:19:45.100 に答える
0

プリミティブを const-reference として渡しても、何も節約できません。ポインタと int は同じ量のメモリを使用します。const-reference を渡すと、マシンはポインタにメモリを割り当て、ポインタ アドレスをコピーする必要があります。これには、整数を割り当ててコピーするのと同じコストがかかります。Date クラスが単一の 64 ビット整数 (または double) を使用して日付を格納する場合、const-reference を使用する必要はありません。ただし、Data クラスがより複雑になり、追加のフィールドを格納する場合、Date オブジェクトを const-reference で渡すと、値で渡すよりもコストが低くなります。

于 2013-07-12T16:23:28.520 に答える