web-dev-qa-db-ja.com

参照渡しと値渡しの違いは何ですか?

違いは何ですか

  1. 参照渡しのパラメータ
  2. 値で渡されるパラメータ

いくつか例を挙げてください。

506
ritu

関数に引数を渡す方法です。参照渡しは、呼び出された関数のパラメータが、呼び出し元が渡した引数と同じになることを意味します(値ではなく、識別情報 - 変数自体)。値渡しは、呼び出された関数のパラメータが呼び出し元の渡された引数のコピーになることを意味します。値は同じになりますが、同一性 - 変数 - は異なります。したがって、ある場合には呼び出された関数によって行われたパラメーターを変更すると、渡された引数が変更され、別の場合には呼び出された関数のパラメーターの値が変更されるだけです(コピーのみ)。急いで:

  • Javaは値渡しのみをサポートします。オブジェクトへの参照をコピーするとき、呼び出された関数のパラメータが同じオブジェクトをポイントし、そしてそのオブジェクトへの変更が呼び出し元に表示される場合でも、常に引数をコピーします。これは混乱を招くことがあるので、 ここ はJon Skeetがこれについて述べなければならないものです。
  • C#は、値渡しと参照渡し(呼び出し元で使用され、関数と呼ばれるキーワードref)をサポートします。 Jon Skeetもこの ここ についてNiceの説明をしています。
  • C++では、値渡しと参照渡し(呼び出し先関数で使用される参照パラメーター型)がサポートされています。あなたはこれについての説明を以下に見つけるでしょう。

コード

私の言語はC++なので、ここでそれを使います。

// passes a pointer (called reference in Java) to an integer
void call_by_value(int *p) { // :1
    p = NULL;
}

// passes an integer
void call_by_value(int p) { // :2
    p = 42;
}

// passes an integer by reference
void call_by_reference(int & p) { // :3
    p = 42;
}

// this is the Java style of passing references. NULL is called "null" there.
void call_by_value_special(int *p) { // :4
    *p = 10; // changes what p points to ("what p references" in Java)
    // only changes the value of the parameter, but *not* of 
    // the argument passed by the caller. thus it's pass-by-value:
    p = NULL;
}

int main() {
    int value = 10;
    int * pointer = &value;

    call_by_value(pointer); // :1
    assert(pointer == &value); // pointer was copied

    call_by_value(value); // :2
    assert(value == 10); // value was copied

    call_by_reference(value); // :3
    assert(value == 42); // value was passed by reference

    call_by_value_special(pointer); // :4
    // pointer was copied but what pointer references was changed.
    assert(value == 10 && pointer == &value);
}

そして、Javaの例では問題ありません。

class Example {
    int value = 0;

    // similar to :4 case in the c++ example
    static void accept_reference(Example e) { // :1
        e.value++; // will change the referenced object
        e = null; // will only change the parameter
    }

    // similar to the :2 case in the c++ example
    static void accept_primitive(int v) { // :2
        v++; // will only change the parameter
    }        

    public static void main(String... args) {
        int value = 0;
        Example ref = new Example(); // reference

        // note what we pass is the reference, not the object. we can't 
        // pass objects. The reference is copied (pass-by-value).
        accept_reference(ref); // :1
        assert ref != null && ref.value == 1;

        // the primitive int variable is copied
        accept_primitive(value); // :2
        assert value == 0;
    }
}

ウィキペディア

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference

この男はかなりそれを釘付けにします:

http://javadude.com/articles/passbyvalue.htm

132

2つの用語を理解する前に、 _は_ を理解する必要があります。すべてのオブジェクトは、それを区別することができる2つのことを持っています。

  • その価値.
  • その住所.

employee.name = "John"と言ったら

nameには2つのことがあることを知っています。その値は"John"であり、メモリ内での位置も16進数であり、0x7fd5d258dd00のようになります。

言語のアーキテクチャやあなたのオブジェクトのtype(class、struct、etc.)に応じて、あなたは"John"0x7fd5d258dd00のどちらかを転送するでしょう。

"John"を渡すことは、値渡しとして知られています。 0x7fd5d258dd00を渡すことは、参照渡しとして知られています。このメモリ位置を指している人はだれでも"John"の値にアクセスできます。

これについての詳細は、 ポインタを間接参照する そして クラス(参照型)よりも構造体(値型)を選ぶ理由について を読むことをお勧めします。/ /

53
Honey

これが一例です。

#include <iostream>

void by_val(int arg) { arg += 2; }
void by_ref(int&arg) { arg += 2; }

int main()
{
    int x = 0;
    by_val(x); std::cout << x << std::endl;  // prints 0
    by_ref(x); std::cout << x << std::endl;  // prints 2

    int y = 0;
    by_ref(y); std::cout << y << std::endl;  // prints 2
    by_val(y); std::cout << y << std::endl;  // prints 2
}
52
pyon

これを実現する最も簡単な方法は、Excelファイルを使用することです。たとえば、セルA1とB1にそれぞれ5と2の2つの数字があり、それらの合計を3番目のセルに求めたいとします。A2としましょう。これには2つの方法があります。

  • その値をセルA2に渡す このセルに= 5 + 2と入力することによって。この場合、セルA1またはB1の値が変化しても、A2の合計は変わりません。

  • または セルA1およびB1の「参照」をセルA2に渡す = A1 + B1と入力します。この場合、セルA1またはB1の値が変わると、A2の合計も変わります。

24
Than Skourtan

Refで渡すときは、基本的に変数へのポインタを渡しています。値を渡して変数のコピーを渡します。基本的な使い方では、これは通常、変数へのrefによる変更が呼び出しメソッドであると見なされ、値によって渡されないことを意味します。

18
Craig

値渡しは指定した変数に格納されているデータのCOPYを送信し、参照渡しは変数自体への直接リンクを送信します。そのため、変数を参照渡ししてから、渡したブロック内で変数を変更すると、元の変数が変更されます。単純に値で渡した場合、元の変数は渡したブロックでは変更できませんが、呼び出し時に含まれていたものはすべてコピーされます。

11
MetaGuru

両者の主な違いは、値型変数は値を格納することです。そのため、メソッド呼び出しで値型変数を指定すると、その変数の値のコピーがメソッドに渡されます。参照型変数はオブジェクトへの参照を格納するため、引数として参照型変数を指定すると、そのオブジェクトを参照する実際の参照のコピーがメソッドに渡されます。参照自体が値渡しされていても、メソッドは受け取った参照を使用して元のオブジェクトと対話し、場合によっては変更することもできます。同様に、return文を介してメソッドから情報を返す場合、メソッドは値型変数に格納されている値のコピー、または参照型変数に格納されている参照のコピーを返します。参照が返されると、呼び出し元のメソッドはその参照を使用して参照先のオブジェクトと対話できます。したがって、実際には、オブジェクトは常に参照によって渡されます。

C#では、呼び出されたメソッドが変数を変更できるように参照によって変数を渡すために、C#はキーワードrefおよびoutを提供します。パラメータ宣言にrefキーワードを適用すると、参照によってメソッドに変数を渡すことができます。呼び出されたメソッドは、呼び出し元の元の変数を変更できます。 refキーワードは、呼び出し元のメソッドですでに初期化されている変数に使用されます。通常、メソッド呼び出しに初期化されていない変数が引数として含まれていると、コンパイラはエラーを生成します。キーワードoutでパラメータの前に出力パラメータを作成します。これは、引数が参照によって呼び出されたメソッドに渡されること、および呼び出されたメソッドが呼び出し元の元の変数に値を割り当てることをコンパイラに示します。このメソッドがすべての実行パスで出力パラメータに値を割り当てないと、コンパイラはエラーを生成します。これは、メソッドへの引数として渡される初期化されていない変数に対してコンパイラがエラーメッセージを生成することも防ぎます。メソッドはreturnステートメントを介して呼び出し元に値を1つだけ返すことができますが、複数の出力(refおよび/またはout)パラメータを指定することによって多くの値を返すことができます。

ここでC#の議論と例を参照してください リンクテキスト

5
Tina Endresen

値渡し - この関数は変数をコピーしてコピーを処理します(したがって、元の変数の内容は変更されません)。

参照渡し - 関数は元の変数を使用します。他の関数で変数を変更すると、元の変数も変更されます。

例(これをコピーして使ってみて、試してみてください):

#include <iostream>

using namespace std;

void funct1(int a){ //pass-by-value
    a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else
}
void funct2(int &a){ //pass-by-reference
    a = 7; //now "a" is 7 both in funct2, main and everywhere else it'll be used
}

int main()
{
    int a = 5;

    funct1(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5
    funct2(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7

    return 0;
}

それを単純にしなさい、のぞき見。テキストの壁は悪い習慣になる可能性があります。

5
user326964

例:

class Dog 
{ 
public:
    barkAt( const std::string& pOtherDog ); // const reference
    barkAt( std::string pOtherDog ); // value
};

const &は一般的に最善です。あなたは建設や破壊のペナルティを負うことはありません。参照がconstではない場合、あなたのインタフェースは、渡されたデータを変更することを示唆しています。

3
DEADFACE

手短に言えば、値渡し(Passed by value)はそれが何であるかであり、参照渡し(reference)で渡されることはどこです。

値がVAR1 = "Happy Guy!"の場合、 "Happy Guy!"だけが表示されます。 VAR1が "Happy Gal!"に変わると、それはわかりません。それが参照によって渡され、VAR1が変更された場合、あなたはそうするでしょう。

2
Monster

値渡しは、引数を使用して関数に値を渡す方法を意味します。値渡しでは、指定した変数に格納されているデータをコピーします。データがコピーされる場合は、参照渡しよりも遅くなります。コピーされたデータを変更しても、元のデータは影響を受けません。参照による受け渡しまたはアドレスによる受け渡しで、変数自体への直接リンクを送ります。またはポインタを変数に渡します。それは速いですbcse少ない時間が消費されます

1

関数に渡した後で元の変数の値を変更したくない場合は、 " pass by value "パラメータを付けて関数を構築する必要があります。

その場合、関数は値のみを持ちますが、渡された変数のアドレスは持ちません。変数のアドレスがないと、関数の内側から見たときに関数の内側のコードが変数の値を変更することはできません。

しかし、外側から見て関数に変数の値を変更する能力を与えたい場合は、 参照渡し を使用する必要があります。値とアドレス(参照)の両方が渡され、関数内で利用可能になるので。

1
Stanley

これは値渡し - ポインタ値 - 参照の違いを示す例です。

void swap_by_value(int a, int b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}   
void swap_by_pointer(int *a, int *b){
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}    
void swap_by_reference(int &a, int &b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}

int main(void){
    int arg1 = 1, arg2 = 2;

    swap_by_value(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 1 2

    swap_by_pointer(&arg1, &arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1

    arg1 = 1;                               //reset values
    arg2 = 2;
    swap_by_reference(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1
}

「参照渡し」メソッドには、重要な制限があります。パラメータが参照渡しとして宣言されている場合(したがって、先頭に&記号が付きます)、対応する実際のパラメータは変数である必要がありますです。

「値渡し」仮パラメータを参照する実パラメータは、一般にである可能性があるため、変数だけでなくリテラルまたは関数呼び出しの結果も使用できます。

関数は、変数以外に値を入れることはできません。リテラルに新しい値を代入したり、式に結果を変更させることはできません。

PS:また、現在のスレッドでDylan Beattieの答えをわかりやすい言葉で確認することもできます。

0
BugShotGG