4

Java では、適切なオブジェクトを含むすべての変数は実際には参照 (つまりポインター) です。したがって、これらのオブジェクトを引数とするメソッド呼び出しは、常に「参照渡し」です。オブジェクトの状態を変更するメソッドを呼び出すと、元のオブジェクト (呼び出し側) にも影響します。

C++ は異なります。ここでは、引数を値渡しまたは参照渡しできます。値渡しされたオブジェクトで mutator メソッドを呼び出しても、元のオブジェクトは影響を受けません。(値による呼び出しはオブジェクトのローカルコピーを作成すると思います)。

したがって、これに対する私の最初の応答 (Java から C++ への移行) は、オブジェクトを引数として使用するときは常にポインターを使用することです。これにより、私が Java に期待するようになった動作が得られます。

ただし、メソッド本体でオブジェクトを変更する必要がない場合は、「値による呼び出し」を使用することもできます。これをやりたい理由はありますか?

4

8 に答える 8

13

オブジェクトを引数として使用するときは常にポインターを使用する

いいえ、C++ では、関数を有効な引数として呼び出すことができない限り、常に参照渡しします。nullptr関数が引数を変更する必要がない場合は、const参照によって渡します。

値による引数の受け渡しには、いくつかの用途があります。

関数で引数のコピーを作成する必要がある場合は、関数内でコピーを作成するよりも、値を渡してこのコピーを作成することをお勧めします。例えば:

void foo( widget const& w )
{
  widget temp( w );
  // do something with temp
}

代わりに使用

void foo( widget w )  // copy is made here
{
  // operate on w itself
}

これを行うと、可能であればコンパイラを移動できるという利点もあり、これは通常、コピーを作成するよりも効率的です。 widget

于 2012-04-22T15:49:07.247 に答える
9

ポインターで渡す必要があるという点で間違っています。参照渡ししたい場合は、まあ...単純に参照渡しします。

void foo(int& x)
{
   x = 3;
}

int main()
{
   int a = 0;
   foo(a);
   assert( a == 3 );
}

また、値渡しは、呼び出されたコンテキスト内で変数を変更できないことを保証することに注意してください。参照渡しもそうですがconst...

于 2012-04-22T15:43:09.473 に答える
3

オブジェクトを値で関数に渡す場合、その関数は、呼び出し元に影響を与えることなく、それらのオブジェクトを「作業」変数として自由に使用できます。

于 2012-04-22T15:43:18.527 に答える
3

Java では、参照はガベージ コレクションされた「スマート ポインター」です。

<memory>C++ は、ライブラリにあるunique_ptrand と呼ばれるスマート ポインターの概念も使用しますshared_ptr。shared_ptr は参照カウントされるため、Java 参照と同じように使用できます。unique_ptr は似ていますが、コピー不可であり、もう少し軽量です。両方の利点は、deleteキーワードを使用する必要がないことと、例外によって保護されている「ポインター」に依存できることです。

C++ は、参照の概念もサポートしています。これは通常、オブジェクトを渡すのに適しています ( constへの参照はさらに優れています)。&C++ での参照は、渡されるオブジェクトの型にバインドされるため、関数シグネチャで(参照記号を使用して) 指定する必要があります。

#include <string>

void foo(std::string& bar)
{
    bar = "world";
}

void foo2(const std::string& bar)
{
    //passed by reference, but not modifyable.
}

int main()
{
    std::string str = "hello";
    foo(str);
    foo2(str);
}

「生の」ポインターについては、スマート ポインター、参照、反復子、または値渡しのいずれかを使用することで、ほぼ常に回避できます。単純な通常のポインターには、C++ が C 言語から継承した「落とし穴」の混合バッグが付属しています-かなり最近のコンパイラーを使用している場合は、それらを実際に使用する必要はまったくありません (次のようなことを行う場合を除きます)。メモリ管理、データ構造などを使用して、学習目的で車輪を再発明する)

于 2012-04-22T15:49:41.520 に答える
3

何かが値であり、値のように振る舞う必要があるため、通常は値で渡します。多くの場合、const 参照による受け渡しは、考慮に値するほど十分に近いものです。それ以外の場合は、そうではありません。

値渡しも最適化の 1 つです。少なくとも IMO では、これは多かれ少なかれ二次的なものですが、とにかく重要になる可能性があります (特に、const 参照による受け渡しと実際の値の受け渡しのどちらかを選択する場合)。

IMO、本当の問題は反対の方向にあるはずです.値を渡すように明確に指示したのに、なぜコンパイラは参照を渡す必要があるのでしょうか? 答えは「時期尚早の最適化」です。Java の設計者 (あなたの例に言及すると、これはほとんどユニークではありません) は、コンパイラに指示されたことを実行させるよりもよく知っていると判断しました。大きなオブジェクトを値で渡すのは遅くなる可能性があり、間違いである可能性があるため、高速である可能性があり、まさに意図したものである可能性がありますが、まったく行わないことにしました。

于 2012-04-22T15:52:17.340 に答える
1

参照渡しの場合、メソッドに渡された値をメソッド内で誤って変更する可能性がある継承の危険性があります。メソッド呼び出しの後、実際にはオブジェクトが変更されたにもかかわらず、メソッドがオブジェクトを変更しなかったと想定できます。

値渡しには、渡すオブジェクトのコピーを作成するため、余分なメモリが必要になるというマイナスの側面があります (そして、わずかなパフォーマンス オーバーヘッドが発生する可能性があります)。メソッド内で変更。

于 2012-04-22T16:38:03.350 に答える
1

関数シグネチャの変数の型を、呼び出し元へのコントラクトと見なす必要があると思います。したがって、次のように機能すると宣言した場合:

void foo( int a );

次に、渡された値を好きなようにコピーし、変更されないと言っています。

次のように宣言した場合:

void foo (int* a);

次に、何aを指すかを変更するか、実際にポインターを変更します

したがって、セマンティックの違いは、関数のコントラクトが何を行うかを宣言し、ポインターと参照を使用して (参照またはポインターが指しているオブジェクトで const を宣言せずに) 変数を変更できることです。

C++ では参照が好まれます。これは、意図していることがより明確になり、ポインターが指している内容を変更する関数にポインターを渡すときに必要な、ポインター関数シグネチャーへの c スタイルのポインターを回避するためです。これにより、エラーとヘッドが発生します。何がうまくいかなかったのかを理解する前に引っ掻いてください。

ただし、ポインターは依然としてパラメーターとして非常に便利です。特に、オブジェクトへのポインターが null かどうかをテストする必要がある場合は、参照を使用することはできません。

于 2012-04-22T15:55:01.237 に答える
0

副作用を避けるのに役立ちます。プログラムでそのような副作用が必要な場合は、参照による呼び出しを使用します。

于 2012-04-22T15:44:16.297 に答える