33

私は Java から C++ に移行しており、言語の柔軟性について少し混乱しています。1 つのポイントは、オブジェクトを格納する方法が 3 つあることです。ポインター、参照、およびスカラーです (正しく理解すれば、オブジェクト自体を格納します)。

私は可能な限り参照を使用する傾向があります。これは、可能な限り Java に近いためです。場合によっては、派生属性のゲッターなど、これは不可能です。

MyType &MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

tのスコープ内にのみ存在するため、これはコンパイルされませんgetSomeAttribute()。参照を返すと、クライアントが使用できるようになる前にどこにもポイントしません。

したがって、次の 2 つのオプションが残っています。

  1. ポインターを返す
  2. スカラーを返す

ポインターを返すと、次のようになります。

MyType *MyClass::getSomeAttribute() {
    MyType *t = new MyType;
    return t;
}

これは機能しますが、クライアントはNULL、参照では必要のないことを確認するために、このポインターをチェックする必要があります。もう 1 つの問題は、呼び出し元tが割り当てが解除されていることを確認する必要があることです。回避できる場合は、それを処理したくありません。

別の方法は、オブジェクト自体 (スカラー) を返すことです。

MyType MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

それは非常に簡単で、この場合に私が望んでいることです。参照のように感じ、null にすることはできません。オブジェクトがクライアントのコードの範囲外にある場合、オブジェクトは削除されます。とても便利です。しかし、そうしている人をほとんど見かけませんが、それには何か理由があるのでしょうか? ポインターや参照の代わりにスカラーを返す場合、何らかのパフォーマンス上の問題はありますか?

この問題を処理するための最も一般的/エレガントなアプローチは何ですか?

4

5 に答える 5

24

値で返します。コンパイラはコピーを最適化して取り除くことができるので、最終結果はあなたが望むものになります。オブジェクトが作成され、呼び出し元に返されます。

人々がこれを行うのをめったに見ない理由は、間違った C++ コードを見ているからだと思います。;) Java から来たほとんどの人は、このようなことをすることに不快感を覚えるので、あちこちに電話をかけnewます。そして、いたるところでメモリ リークが発生し、NULL やその他の原因となるすべての問題をチェックする必要があります。:)

C++ 参照は Java 参照とほとんど共通点がないことも指摘しておく価値があります。Java での参照は、ポインターに非常に似ています (再配置または NULL に設定できます)。実際、唯一の本当の違いは、ポインターがガベージ値も指すことができること (初期化されていない場合、またはスコープ外になったオブジェクトを指している場合)、およびポインターに対してポインター演算を実行して、配列。C++ 参照は、オブジェクトのエイリアスです。Java 参照はそのようには動作しません。

于 2010-08-07T18:11:07.707 に答える
3

簡単に言えば、new可能な限りポインターと動的割り当てを使用しないようにします。代わりに、値、参照、および自動的に割り当てられたオブジェクトを使用してください。もちろん、動的割り当てを常に回避できるわけではありませんが、最初の手段ではなく、最後の手段にする必要があります。

于 2010-08-07T18:12:47.607 に答える
2

値で返すと、オブジェクトをコピーする必要があるため、パフォーマンスが低下する可能性があります。リストのような大きなオブジェクトの場合、その操作は非常に高価になる可能性があります。

しかし、最新のコンパイラは、これが起こらないようにするのに非常に優れています。C++ 標準では、コンパイラが特定の状況でコピーを省略できると明示的に述べています。あなたが与えたサンプルコードに関連する特定のインスタンスは、「戻り値の最適化」と呼ばれます。

::std::auto_ptr個人的には、メンバー変数を返すときは (通常は const) 参照によって戻り、何かを動的に割り当てる必要があるときは、ある種のスマート ポインター オブジェクト (多くの場合) を返します。それ以外の場合は、値で返します。

また、参照パラメーターを頻繁にconst使用しますが、これは C++ では非常に一般的です。これは、パラメーターを渡し、「関数がこれに触れることは許可されていません」と言う方法です。基本的に読み取り専用パラメーターです。ただし、単一の整数またはポインターよりも複雑なオブジェクトにのみ使用する必要があります。

constJava からの大きな変更点の 1 つは、それが重要であり、非常に頻繁に使用されていることだと思います。それを理解し、それをあなたの友達にすることを学びましょう。

また、可能な限り動的割り当てを回避することが良い考えであるというニールの答えは正しいと思います。それを実現するためにデザインを過度にゆがめるべきではありませんが、それが起こる必要のないデザインの選択を確実に優先する必要があります。

于 2010-08-07T18:20:20.803 に答える
0

値または参照による受け渡しに関するポイント:
最適化を考慮して、関数がinlineであると仮定すると、そのパラメーターが「const DataType objectName」として宣言されている場合、その DataType はプリミティブであっても何でもかまいません。オブジェクトのコピーは含まれません。そのパラメーターが「const DataType & objectName」または「DataType & objectName」として宣言されている場合、DataType はプリミティブであっても何でもかまいませんが、アドレスの取得やポインターは関与しません。前の両方のケースで、入力引数はアセンブリ コードで直接使用されます。

参照に関するポイント:
参照は常にポインターであるとは限りません。たとえば、関数の本体に次のコードがある場合、参照はポインターではありません。

int adad=5;
int & reference=adad;  

値による戻りに​​関するポイント:
一部の人々が言及したように、最適化機能を備えた優れたコンパイラを使用すると、任意の型の値による戻りに​​よって余分なコピーが発生することはありません。

参照による戻りに​​関するポイント:インライン
関数と最適化 の場合、参照による戻りに​​はアドレスの取得やポインターは含まれません。

于 2010-08-07T20:10:56.077 に答える
0

値による戻りは、C++ で実践されている一般的なことです。ただし、オブジェクトを渡すときは参照渡しです。

 main()
   {

       equity trader;

       isTraderAllowed(trader);

       ....
    }

    bool isTraderAllowed(const equity& trdobj)
    {
             ... // Perform your function routine here.
    }

上記は、オブジェクトを参照渡しする簡単な例です。実際には、クラス エクイティに対して isTraderAllowed というメソッドがありますが、参照渡しの実際の使用法を示していました。

于 2010-08-07T18:19:41.887 に答える