参照とポインターを使用する場合


381

ポインタと参照の構文と一般的なセマンティクスを理解していますが、APIで参照またはポインタを使用することが適切かどうかをどのように判断すればよいですか?

当然、状況によってはどちらか一方が必要です(operator++参照引数が必要です)が、変数が破壊的に渡されていることは構文上明らかであるため、一般的にはポインタ(およびconstポインタ)を使用した方がよいと思います。

たとえば、次のコードで:

void add_one(int& n) { n += 1; }
void add_one(int* const n) { *n += 1; }
int main() {
  int a = 0;
  add_one(a); // Not clear that a may be modified
  add_one(&a); // 'a' is clearly being passed destructively
}

ポインターを使用すると、何が起こっているのかが常に(さらに)明白になります。そのため、APIなどでは、明確さを重視する場合、ポインターは参照よりも適切ではありませんか?つまり、参照は必要な場合にのみ使用する必要があるということoperator++ですか(例:)?どちらか一方にパフォーマンスの問題はありますか?

編集(古い):

NULL値を許可して生の配列を処理する以外に、選択は個人の好みに帰着するようです。GoogleのC ++スタイルガイドを参照する以下の回答を受け入れました。「値の構文はあるがポインタのセマンティクスがあるため、参照は混乱を招く可能性がある」という見解を示しているためです。

NULLであってはならないポインタ引数をサニタイズするために必要な追加の作業(たとえばadd_one(0)、実行時にポインタバージョンを呼び出して中断する)のため、オブジェクトが存在しなければならない参照を使用することは保守性の観点からは残念ですが、意味があります。構文の明確さを失う。


4
どちらをいつ使用するかについては、すでに決定しているようです。個人的には、変更するかどうかに関係なく、操作しているオブジェクトを渡すことを好みます。関数がポインターを受け取る場合、それはそれがポインターに作用している、つまり配列内のイテレーターとしてそれらを使用していることを教えてくれます。
ベンジャミンリンドリー2011

1
@Schnommus:かなり公平ですが、私はほとんどTextMateを使用しています。それでも、一目でその意味がわかるのが望ましいと思います。
connec

4
どうadd_one(a);ということは不明であるaのを修正することになるだろうか?それはコードの中で正しく言っています:1つ追加してください
GManNickG 2011

32
@connec:Google C ++スタイルガイドは、優れたC ++スタイルガイドとは見なされません。これは、Googleの古いC ++コードベースを操作するためのスタイルガイドです(つまり、それらのコードに適しています)。それに基づいて答えを受け入れることは、誰の助けにもなりません。あなたがすでに決められた意見でこの質問に来たあなたのコメントと説明を読むだけで、あなたの意見を確認するために他の人を探しています。その結果、あなたは質問に基づいて、あなたが聞きたい/期待するものに答えます。
マーティンヨーク

1
これは、メソッドに名前を付けることで簡単に修正できaddOneTo(...)ます。それがあなたがしたいことではない場合は、宣言を見てください。
ステファン2013年

回答:


296

できる限り参照を使用し、必要な場合はポインタを使用します。

できなくなるまでポインタを避けてください。

その理由は、ポインターが他の構成要素よりも物事の追跡/読み取りを難しくし、安全性が低く、はるかに危険な操作になるためです。

したがって、経験則では、他に選択肢がない場合にのみポインタを使用します。

たとえば、オブジェクトへのポインタを返すことは、関数がnullptrを返すことができ、そうであると想定されている場合に有効なオプションです。とはいえ、より良いオプションはに似たものを使用することboost::optionalです。

別の例は、特定のメモリ操作のためにrawメモリへのポインタを使用することです。これはコードの非常に狭い部分に隠してローカライズする必要があります。これにより、コードベース全体の危険な部分を制限できます。

あなたの例では、ポインタを引数として使用しても意味がありません:

  1. nullptr引数として提供する場合、未定義の動作の領域に入ります。
  2. 参照属性バージョンは、1の問題を(トリックを簡単に見つけることなしに)許可しません。
  3. 参照属性のバージョンは、ユーザーにとって理解しやすいです。nullになる可能性があるものではなく、有効なオブジェクトを提供する必要があります。

関数の動作が特定のオブジェクトの有無にかかわらず機能する必要がある場合、属性としてポインターを使用するnullptrと、引数として渡すことができ、関数には問題ありません。これは、ユーザーと実装の間の一種の契約です。


49
ポインタが何かを読みにくくするかどうかはわかりませんか?これはかなり単純な概念であり、何かが変更される可能性が高いときにそれを明確にします。何が起こっているかの兆候がないときに読むのが難しいと私が思うadd_one(a)ことは、参照によって設定するのではなく、なぜ結果を返すべきではないのですか?

46
@connec:add_one(a)が混乱している場合は、名前が正しくないためです。add_one(&a)同じ混乱がありますが、オブジェクトではなくポインタをインクリメントしている可能性があります。add_one_inplace(a)すべての混乱を避けるでしょう。
Nicol Bolas、2011

20
1つの点として、参照は、ポインターと同じくらい簡単に消えるメモリを参照できます。したがって、ポインタよりも安全である必要はありません。参照を永続化して渡すことは、ポインタと同じくらい危険です。
Doug T.

6
@Klaim私は生のポインタを意味しました。C ++にはポインターがNULLありnullptr、それには理由があります。また、「ポインタを使用しない」、「NULLを使用しない、常に使用するboost::optional」、またはそのいずれかを行うことは、十分に検討された、または現実的なアドバイスではありません。それは正気ではない。誤解しないでください。生のポインターがC ++で必要とされる頻度はCより少ないですが、それでも有用です。C++の一部の人が主張するほど「危険」ではありません(これも誇張です)。ポインタを使用しreturn nullptr;て欠損値を示す方が簡単な場合...なぜBoost全体をインポートするのですか?

5
@Klaim「NULLを使用することは悪い習慣です」-今はとんでもないことです。そしてif時代遅れでありwhile() { break; }、代わりに使うべきですよね?また、心配する必要はありません。大規模なコードベースを確認して作業してきました。もちろん、あなたが不注意だとしたら、所有権が問題になります。ただし、規則に固執する場合は、規則を一貫して使用し、コードにコメントを付けて文書化してください。しかし、結局のところ、私はC ++には馬鹿すぎるので、Cを使用する必要があります。

62

リファレンスはポインタとして内部的に実装されているため、パフォーマンスはまったく同じです。したがって、そのことを心配する必要はありません。

参照とポインタをいつ使用するかに関して、一般に受け入れられている規約はありません。場合によっては、参照を返すか受け入れる必要がありますが(コピーコンストラクターなど)、それ以外は自由に行うことができます。私が遭遇したかなり一般的な規則は、パラメーターが既存のオブジェクトを参照する必要がある場合に参照を使用し、NULL値に問題がない場合にポインターを使用することです。

Googleのような)いくつかのコーディング規約では、参照には少し不明確な構文があるため、常にポインタまたはconst参照を使用する必要があると規定されています。参照の動作には値の構文があります。


10
これに少し追加すると、Googleのスタイルガイドでは、関数への入力パラメーターはconst参照であり、出力はポインターである必要があると述べています。これが好きなのは、関数のシグネチャを読み取ると、入力と出力を明確に区別できるからです。
Dan

44
@ダン:GoogleスタイルガイドはGoogleの古いコード用であり、最新のコーディングには使用しないでください。実際、これは新しいプロジェクトにとってはかなり悪いコーディングスタイルです。
GManNickG 2011

13
@connec:このように言いましょう:nullは完全に有効なポインター値です。ポインターがあるところならどこでも、私はそれに値nullを与えることができます。Ergoの2番目のバージョンadd_one壊れています:add_one(0); // passing a perfectly valid pointer value、kaboom。nullかどうかを確認する必要があります。一部の人々は、「まあ、私は自分の関数がnullでは機能しないことを文書化します」と反論するでしょう。それは問題ありませんが、質問の目的に反します。ドキュメントを参照してnullが問題ないかどうかを確認する場合は、関数宣言も表示されます
GManNickG 2011

8
それが参照である場合は、それが事実であることがわかります。ただし、そのようなレトルトは要点を逃しています。参照は言語レベルで既存のオブジェクトを参照することを強制ます。ポインタにはそのような制限はありませんが、nullではない可能性があります。言語レベルの強制は、ドキュメントレベルの強制よりも強力で、エラーが発生しにくいことは明らかです。「ルックは、null参照:いくつかは言うことによってこれをレトルトにしようとしますint& i = *((int*)0);。これは、有効なレトルトでないポインタを使用して、前のコード嘘では問題ではなく、参照して。参照は、ヌル、期間は決してありません。
GManNickG

12
こんにちは、私はコメントに言語弁護士の不足を見たので、是正させてください:参照は通常ポインターによって実装されますが、標準はそのようなことを述べていません。他のメカニズムを使用した実装は、100%不満になります。
Thomas Bonini、2011

34

C ++よくある質問Liteと -

可能な場合は参照を使用し、必要な場合はポインタを使用します。

「再装着」する必要がない場合は常に、ポインタよりも参照が優先されます。これは通常、参照がクラスのパブリックインターフェイスで最も役立つことを意味します。参照は通常、オブジェクトのスキンに表示され、ポインタは内部に表示されます。

上記の例外は、関数のパラメーターまたは戻り値に「センチネル」参照(オブジェクトを参照しない参照)が必要な場合です。これは通常、ポインタを返す/取得し、NULLポインタにこの特別な意味を与えることによって行うのが最適です(参照は、逆参照されたNULLポインタではなく、常にオブジェクトをエイリアスする必要があります)。

注:古い行のCプログラマーは、呼び出し元のコードで明示的ではない参照セマンティクスを提供するため、参照を好まない場合があります。ただし、C ++の使用経験があると、これは情報の隠蔽の一種であり、これは負債ではなく資産であることにすぐに気付きます。たとえば、プログラマは、マシンの言語ではなく、問題の言語でコードを書く必要があります。


1
APIを使用している場合は、APIの機能に精通し、渡されたパラメーターが変更されているかどうかを知っている必要があると思われるかもしれませんが、私はCプログラマー( Cの経験はほとんどありませんが)。ただし、より明確な構文は、マシンだけでなくプログラマーにとっても有益です。
connec

1
@connec:Cプログラマーが自分の言語に合っていることを確認してください。しかし、C ++をCとして扱うことを間違えないでください。それは完全に異なる言語です。C ++をCとして扱うと、同じように参照されるものC with class(C ++ではない)を書くことになります。
マーティンヨーク

15

私の経験則は:

  • 発信または入出力パラメーターにはポインターを使用します。したがって、値が変更されることがわかります。(を使用する必要があります&
  • NULLパラメータが許容値である場合は、ポインタを使用してください。(constそれが着信パラメーターであるかどうかを確認してください)
  • NULLにできず、プリミティブ型(const T&)ではない場合は、着信パラメーターの参照を使用します。
  • 新しく作成されたオブジェクトを返すときは、ポインターまたはスマートポインターを使用します。
  • 参照の代わりに、構造体またはクラスのメンバーとしてポインターまたはスマートポインターを使用します。
  • エイリアスの参照を使用します(例int &current = someArray[i]

どちらを使用するかに関係なく、関数が明確でない場合は、関数とそのパラメーターの意味を文書化することを忘れないでください。


14

免責事項:参照をNULLにすることも "リバウンド"にすることもできない(つまり、それらがエイリアスであるオブジェクトを変更できないことを意味する)以外は、実際には好みの問題であるため、ここでは触れません。 "これの方が良い"。

とは言っても、コードが参照によって明確性を失うとは思わないという点で、投稿の最後のステートメントに同意しません。あなたの例では、

add_one(&a);

より明確かもしれません

add_one(a);

最も可能性が高いのはaの値が変化することを知っているからです。一方、関数のシグネチャは

void add_one(int* const n);

どちらかははっきりしない:nは単一の整数か配列か?時々、(不十分に文書化された)ヘッダーと次のような署名のみにアクセスできます

foo(int* const a, int b);

一目で解釈するのは容易ではありません。

Imho、(前に説明した意味で)(再)割り当ても再バインドも必要ない場合、参照はポインタと同じくらい優れています。さらに、開発者が配列にポインタのみを使用する場合、関数のシグネチャはややあいまいさが少なくなります。演算子の構文は参照を使用すると読みやすくなることは言うまでもありません。


両方のソリューションが明確性を得る場所と失う場所を明確に示してくれてありがとう。私は最初はポインターキャンプにいましたが、これは非常に理にかなっています。
Zach Beavon-Collin 2016

12

他の人がすでに答えたように:NULL/である変数nullptr本当に有効な状態でない限り、常に参照を使用します。

主題に関するジョン・カーマックの視点は同様です:

NULLポインターは、C / C ++での最大の問題であり、少なくとも私たちのコードではそうです。フラグとアドレスの両方として単一の値を二重に使用すると、非常に多くの致命的な問題が発生します。C ++参照は、可能な場合は常にポインタよりも優先する必要があります。参照は「本当に」単なるポインタですが、非NULLであるという暗黙の規約があります。ポインタが参照に変わったときにNULLチェックを実行します。その後、問題を無視できます。

http://www.altdevblogaday.com/2011/12/24/static-code-analysis/

2012-03-13を編集

ユーザーBret Kuhnsが正しく発言:

C ++ 11標準が完成しました。このスレッドでは、ほとんどのコードが参照、shared_ptr、unique_ptrの組み合わせで完全に問題なく機能することを説明するときがきたと思います。

確かに真実ですが、生のポインタをスマートポインタに置き換えても、問題は残ります。

たとえば、両方std::unique_ptrstd::shared_ptrそのデフォルトコンストラクタによる「空」のポインタのように構成することができます。

...それらが空でないことを確認せずにそれらを使用することはクラッシュの危険を冒すことを意味します、それはまさにJ.カーマックの議論がすべてについてです。

そして、「スマートポインターを関数パラメーターとして渡すにはどうすればよいか」というおもしろい問題があります。

質問C ++ に対するJon回答-boost :: shared_ptrへの参照を渡すこと、および次のコメントは、それでも、スマートポインターをコピーまたは参照によって渡すことは、希望するほど明確ではないことを示しています(私は「デフォルトでは「参照」ですが、間違っている可能性があります)。


1
C ++ 11標準が完成しました。このスレッドで、ほとんどのコードが参照、、shared_ptrおよびの組み合わせで完全に問題なく機能することを説明するときがきたと思いますunique_ptr。所有権のセマンティクスと入出力パラメーターの規則は、これら3つの要素と定数の組み合わせによって処理されます。レガシーコードと非常に最適化されたアルゴリズムを処理する場合を除いて、C ++では生のポインターはほとんど必要ありません。それらが使用されるこれらの領域は、可能な限りカプセル化し、生のポインタを意味的に適切な「最新の」同等のものに変換する必要があります。
Bret Kuhns 2012

1
多くの場合、スマートポインタは渡されるべきではありませんが、nullかどうかをテストしてから、含まれているオブジェクトを参照渡しする必要があります。実際にスマートポインターを渡す必要があるのは、別のオブジェクトと所有権を転送(unique_ptr)または共有(shared_ptr)するときだけです。
ルーク・ワース

@povman:私は完全に同意します:所有権がインターフェイスの一部ではない場合(そして、変更されない限り、変更しないでください)、パラメーター(または戻り値)としてスマートポインターを渡さないでください。所有権がインターフェースの一部である場合、状況は少し複雑になります。たとえば、sutter / Meyersは、unique_ptrをパラメーターとして渡す方法について議論しています:コピー(Sutter)またはr値参照(Meyers)アンチパターンは、グローバルshared_ptrへのポインターを渡すことに依存しています。そのポインターが無効になるリスクがあります(ソリューションはスタック上のスマートポインターをコピーしています)
paercebal

7

それは好みの問題ではありません。ここにいくつかの決定的なルールがあります。

宣言されたスコープ内で静的に宣言された変数を参照する場合は、C ++参照を使用すると、完全に安全になります。同じことが、静的に宣言されたスマートポインタにも当てはまります。参照によるパラメーターの受け渡しは、この使用法の例です。

宣言されているスコープよりも広いスコープから何かを参照する場合は、完全に安全にするために、参照カウントされたスマートポインターを使用する必要があります。

構文上の便宜上、コレクションの要素を参照で参照できますが、安全ではありません。要素はいつでも削除できます。

コレクションの要素への参照を安全に保持するには、参照カウント付きスマートポインターを使用する必要があります。


5

パフォーマンスの違いは非常に小さいため、あまり明確でないアプローチを使用しても正当化されません。

まず、言及が一般的に優れているとは言われなかった1つのケースは、const言及です。非単純型の場合は、const reference avoidをと一時的な作成回避され、懸念される混乱を引き起こしません(値が変更されないため)。ここで、人にポインターを強制的に渡させると、心配されている非常に混乱を引き起こします。関数に渡されて渡されたアドレスを確認すると、値が変更されたと思われる場合があるためです。

いずれにしても、私は基本的にあなたに同意します。関数が何をしているのかがはっきりしない場合、関数が参照を使用して値を変更するのは好きではありません。その場合、私もポインタを使用することを好みます。

複合型で値を返す必要がある場合、私は参照を好む傾向があります。例えば:

bool GetFooArray(array &foo); // my preference
bool GetFooArray(array *foo); // alternative

ここでは、関数名によって、配列で情報を取得していることがわかります。だから混乱はありません。

参照の主な利点は、常に有効な値を含み、ポインタよりもクリーンで、追加の構文を必要とせずに多態性をサポートすることです。これらの利点のいずれも当てはまらない場合、ポインターよりも参照を優先する理由はありません。


4

wikiからコピー-

この結果、多くの実装では、参照を通じて自動または静的存続期間を持つ変数を操作することは、構文的には直接アクセスすることに似ていますが、コストのかかる隠れた逆参照操作を伴う可能性があります。参照は、識別子の間接参照レベルを覆い隠すため、C ++の構文的に論争の的になっている機能です。つまり、ポインタが通常構文的に目立つCコードとは異なり、C ++コードの大きなブロックでは、アクセスされているオブジェクトがローカル変数またはグローバル変数として定義されているか、それが(暗黙のポインタ)への参照であるかどうかがすぐにわかりません。他の場所、特にコードで参照とポインタが混在している場合。この側面により、不十分に記述されたC ++コードの読み取りとデバッグが困難になる可能性があります(エイリアスを参照)。

私はこれに100%同意します。そのため、非常に正当な理由がある場合にのみ参照を使用する必要があると私は信じています。


私も大部​​分は同意しますが、NULLポインターに対する組み込みの保護を失うことは、特に-より明示的ですが-ポインター構文がかなり醜いので、純粋に構文上の懸念には少し高すぎるとの見方に回りますとにかく。
connec

状況も重要な要素になると思います。現在のコードベースが主にポインターを使用しているときに参照を使用しようとするのは悪い考えだと思います。彼らのように暗黙のは、多分それほど重要であることをあなたが彼らの参照であることを期待した場合、その後事実...
user606723

3

留意点:

  1. ポインタは可能ですがNULL、参照はできませんNULL

  2. 参照は使いやすく、const値を変更したくないが、関数で参照が必要な場合に参照に使用できます。

  3. aと共に使用される*while参照で使用されるポインタ&

  4. ポインター算術演算が必要な場合は、ポインターを使用します。

  5. void型へのポインタは使用できますが、void型int a=5; void *p = &a;への参照は使用できません。

ポインターとリファレンス

void fun(int *a)
{
    cout<<a<<'\n'; // address of a = 0x7fff79f83eac
    cout<<*a<<'\n'; // value at a = 5
    cout<<a+1<<'\n'; // address of a increment by 4 bytes(int) = 0x7fff79f83eb0
    cout<<*(a+1)<<'\n'; // value here is by default = 0
}
void fun(int &a)
{
    cout<<a<<'\n'; // reference of original a passed a = 5
}
int a=5;
fun(&a);
fun(a);

何をいつ使用するかの判断

ポインタ:配列、リンクリスト、ツリー実装、およびポインタ演算用。

参照:関数のパラメーターと戻り値の型。


2

可能な限り参照を使用する」ルールに問題があり、さらに使用するために参照を保持したい場合に発生します。例でこれを説明するために、次のクラスがあるとします。

class SimCard
{
    public:
        explicit SimCard(int id):
            m_id(id)
        {
        }

        int getId() const
        {
            return m_id;
        }

    private:
        int m_id;
};

class RefPhone
{
    public:
        explicit RefPhone(const SimCard & card):
            m_card(card)
        {
        }

        int getSimId()
        {
            return m_card.getId();
        }

    private:
        const SimCard & m_card;
};

RefPhone(const SimCard & card)コンストラクターに間違った/ nullポインターを渡さないようにするため、最初はコンストラクターのパラメーターを参照で渡すことをお勧めします。どういうわけか、スタックへの変数の割り当てを促進し、RAIIの利点を活用します。

PtrPhone nullPhone(0);  //this will not happen that easily
SimCard * cardPtr = new SimCard(666);  //evil pointer
delete cardPtr;  //muahaha
PtrPhone uninitPhone(cardPtr);  //this will not happen that easily

しかしその後、一時的なものがあなたの幸せな世界を破壊するようになります。

RefPhone tempPhone(SimCard(666));   //evil temporary
//function referring to destroyed object
tempPhone.getSimId();    //this can happen

したがって、盲目的に参照に固執する場合は、無効なポインターを渡す可能性と、破棄されたオブジェクトへの参照を格納する可能性とをトレードオフします。これは、基本的に同じ効果があります。

編集:私は「できる限り参照を使用し、必要な場合はポインタを使用します。使用できないまでポインタを使用しない」というルールに固執したことに注意してください。最も賛成され、受け入れられた回答から(他の回答も示唆しています)。当然のことですが、例は、参照自体が悪いことを示すことではありません。ただし、ポインタと同じように悪用され、独自の脅威をコードにもたらす可能性があります。


ポインタと参照には以下の違いがあります。

  1. 変数の受け渡しに関しては、参照渡しは値渡しのように見えますが、ポインターのセマンティクスがあります(ポインターのように動作します)。
  2. 参照を直接0(null)に初期化することはできません。
  3. 参照(参照、参照されていないオブジェクト)は変更できません( "* const"ポインターと同等)。
  4. const参照は一時パラメータを受け入れることができます。
  5. ローカルconst参照は一時オブジェクトの寿命を延ばします

それらを考慮に入れて私の現在のルールは以下の通りです。

  • 関数スコープ内でローカルに使用されるパラメーターの参照を使用します。
  • 0(null)が許容可能なパラメーター値である場合、または後で使用するためにパラメーターを格納する必要がある場合は、ポインターを使用します。0(null)が許容できる場合は、パラメーターに "_n"サフィックスを追加するか、保護されたポインター(QtのQPointerのような)を使用するか、ドキュメント化します。スマートポインターを使用することもできます。共有ポインターは通常のポインターよりもさらに注意する必要があります(そうしないと、設計によってメモリリークと責任の混乱が発生する可能性があります)。

3
この例の問題は、参照が安全でないことではなく、プライベートメンバーを存続させるために、オブジェクトインスタンスのスコープ外のものに依存していることです。const SimCard & m_card;ただひどく書かれたコードです。
plamenko 2016年

@plamenko例の目的が理解できないのは残念です。const SimCard & m_card正しいかどうかはコンテキストに依存します。この投稿のメッセージは、参照が安全ではないということではありません(一生懸命に試みた場合にそうなる可能性があります)。メッセージは、「可能な限り参照を使用する」というマントラに盲目的に固執するべきではないということです。例は、「可能な限り参照を使用する」という教義の積極的な使用の結果です。これは明確なはずです。
DOC

私はあなたがその問題についてもっと学ぼうとする人を誤解させるかもしれないと思うので、あなたの答えに私を悩ませる2つのことがある。1.投稿は一方向であり、参照が悪いという印象を簡単に得ることができます。参照を使用しない方法の例を1つだけ提供しました。2.あなたの例では、何が悪いのかはっきりしていませんでした。はい、一時的にdestroyetを取得しますが、間違っていたのはその行ではなく、クラスの実装です。
plamenko

のようなメンバーは実質的に存在してはなりませんconst SimCard & m_card。一時を効率的に使用したい場合は、explicit RefPhone(const SimCard&& card)コンストラクターを追加します。
plamenko

@plamenkoあなたがいくつかの基本的な理解で読むことができないならば、あなたは単に私の投稿によって誤解されるよりも大きな問題を抱えています。どうすればもっと明確にできるかわかりません。最初の文を見てください。「可能な限り参照を使用する」というマントラに問題があります!私の投稿のどこで、参照が悪いという発言を見つけましたか?私の投稿の最後に、参照を使用する場所を書いたので、どのようにしてそのような結論に至ったのですか?これは質問に対する直接の答えではありませんか?
文書、

1

以下はいくつかのガイドラインです。

関数は渡されたデータを変更せずに使用します。

  1. 組み込みデータ型や小さな構造など、データオブジェクトが小さい場合は、値で渡します。

  2. データオブジェクトが配列の場合は、それが唯一の選択肢なので、ポインターを使用します。ポインタをconstへのポインタにします。

  3. データオブジェクトが適切なサイズの構造である場合は、constポインターまたはconst参照を使用してプログラムの効率を高めます。構造またはクラスデザインのコピーに必要な時間とスペースを節約できます。ポインタまたは参照をconstにします。

  4. データオブジェクトがクラスオブジェクトの場合は、const参照を使用します。クラス設計のセマンティクスでは、参照を使用する必要があることがよくあります。これが、C ++がこの機能を追加した主な理由です。したがって、クラスオブジェクトの引数を渡す標準的な方法は参照です。

関数は呼び出し元の関数のデータを変更します。

1.データオブジェクトが組み込みデータ型の場合は、ポインタを使用します。xがintであるfixit(&x)のようなコードを見つけた場合、この関数がxを変更することを意図していることは明らかです。

2.データオブジェクトが配列の場合は、唯一の選択肢であるポインタを使用します。

3.データオブジェクトが構造体の場合は、参照またはポインタを使用します。

4.データオブジェクトがクラスオブジェクトの場合は、参照を使用します。

もちろん、これらは単なるガイドラインであり、異なる選択をする理由があるかもしれません。たとえば、cinは基本タイプの参照を使用するため、cin >>&nの代わりにcin >> nを使用できます。


0

参照はよりクリーンで使いやすく、情報を非表示にする機能が向上しています。ただし、参照を再割り当てすることはできません。最初に1つのオブジェクトを指し、次に別のオブジェクトを指す必要がある場合は、ポインターを使用する必要があります。参照をnullにすることはできないため、問題のオブジェクトがnullである可能性がある場合は、参照を使用しないでください。ポインタを使用する必要があります。自分でオブジェクト操作を処理する場合、つまりスタックではなくヒープ上のオブジェクトにメモリ領域を割り当てる場合は、ポインタを使用する必要があります。

int *pInt = new int; // allocates *pInt on the Heap

0

適切に書かれた例は次のようになります

void add_one(int& n) { n += 1; }
void add_one(int* const n)
{
  if (n)
    *n += 1;
}

そのため、できれば参照が望ましいです...


-1

ちょうど私のダイムを入れて。私はテストを実行しました。それでこっそりしたもの。参照を使用するのではなく、ポインタを使用して、g ++に同じミニプログラムのアセンブリファイルを作成させるだけです。出力を見ると、まったく同じです。シンボルの命名以外。したがって、パフォーマンスを(簡単な例で)調べても問題はありません。

次に、ポインタと参照のトピックについて説明します。私見何よりも透明性が高いと思います。暗黙の行動を読むとすぐに、つま先がカールし始めます。参照をNULLにすることはできないことは、暗黙の振る舞いであることに同意します。

NULLポインターの逆参照は問題ではありません。アプリケーションがクラッシュし、デバッグが容易になります。より大きな問題は、無効な値を含む初期化されていないポインタです。これにより、メモリの破損が発生し、明確な原因のない未定義の動作が発生する可能性があります。

これは、参照がポインタよりもはるかに安全だと私が思うところです。また、インターフェイス(明確に文書化する必要があります。契約による設計を参照してください、Bertrand Meyer)は、関数へのパラメーターの結果を定義するという以前の説明に同意します。これをすべて考慮に入れて、私の好みは可能な限り/いつでも参照を使用することに行きます。


-2

ポインターの場合、何かを指す必要があるため、ポインターはメモリスペースを消費します。

たとえば、整数ポインタを取る関数は整数変数を取りません。そのため、関数に渡すには、まずそのポインタを作成する必要があります。

参考までに、メモリの消費はありません。整変数があり、それを参照変数として渡すことができます。それでおしまい。特別に参照変数を作成する必要はありません。


4
いいえ。ポインターを取る関数は、ポインター変数の割り当てを必要としません&address。一時を渡すことができます。参照がオブジェクトのメンバーである場合、参照はメモリを消費します。さらに、既存のすべてのコンパイラーは実際に参照をアドレスとして実装しているため、パラメーターの受け渡しや逆参照に関しても何も節約できません。
underscore_d
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.