web-dev-qa-db-ja.com

参照渡し/ C ++の値

値と参照の違いを明確にしたいと思います。

絵を描きました

enter image description here

ですから、値渡しするために、

同一のオブジェクトのコピーが異なる参照で作成され、ローカル変数に新しい参照が割り当てられ、新しいコピーを指すようにします

単語を理解する方法:「関数がその値を変更する場合、値と参照による受け渡しの両方について、呼び出し関数のスコープ内でも変更が表示されます」

ありがとう!

35
user36064

passed by referenceの意味を伝えないことで、多くの混乱が生じると思います。 参照渡しと言う人は、通常、引数自体ではなく、参照されているオブジェクトを意味します。参照渡しは、呼び出し先でオブジェクトを変更できないことを意味すると言う人もいます。例:

struct Object {
    int i;
};

void sample(Object* o) { // 1
    o->i++;
}

void sample(Object const& o) { // 2
    // nothing useful here :)
}

void sample(Object & o) { // 3
    o.i++;
}

void sample1(Object o) { // 4
    o.i++;
}

int main() {
    Object obj = { 10 };
    Object const obj_c = { 10 };

    sample(&obj); // calls 1
    sample(obj) // calls 3
    sample(obj_c); // calls 2
    sample1(obj); // calls 4
}

1と3は参照渡しであり、2は値渡しであると主張する人もいます。オブジェクト自体はコピーされないため、別のグループは、最後を除くすべてが参照渡しであると言います。

ここで、私が主張していることを定義します参照渡し。それに関する一般的な概要はここにあります: 参照渡しと値渡しの違い 。最初と最後は値渡しで、中央の2つは参照渡しです。

    sample(&obj);
       // yields a `Object*`. Passes a *pointer* to the object by value. 
       // The caller can change the pointer (the parameter), but that 
       // won't change the temporary pointer created on the call side (the argument). 

    sample(obj)
       // passes the object by *reference*. It denotes the object itself. The callee
       // has got a reference parameter.

    sample(obj_c);
       // also passes *by reference*. the reference parameter references the
       // same object like the argument expression. 

    sample1(obj);
       // pass by value. The parameter object denotes a different object than the 
       // one passed in.

私は次の定義に投票します:

引数(1.3.1)は、呼び出される関数の対応するパラメーターが参照型である場合にのみ参照によって渡されますand参照パラメーターは、引数式に直接バインドします(8.5.3/4) 。その他の場合はすべて、値渡しによる処理を行う必要があります。

これは、以下が値渡しであることを意味します。

void f1(Object const& o);
f1(Object()); // 1

void f2(int const& i);
f2(42); // 2

void f3(Object o);
f3(Object());     // 3
Object o1; f3(o1); // 4

void f4(Object *o);
Object o1; f4(&o1); // 5

1は直接バインドされていないため、値渡しです。実装は一時をコピーしてから、その一時を参照にバインドできます。 2は、実装がリテラルの一時を初期化してから参照にバインドするため、値渡しです。 3は値渡しです。これは、パラメーターに参照型がないためです。 4は同じ理由で値渡しされます。 5は、パラメーターが参照型を取得していないため、値渡しです。以下のケースは、参照によって渡されます(8.5.3/4などのルールによる)。

void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1

void f2(Object const& op);
Object b; f2(b); // 2

struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference

値渡しする場合:

void func(Object o);

そして、呼び出す

func(a);

スタック上にObjectを構築し、funcの実装内でoによって参照されます。これはまだ浅いコピーである可能性があります(aoの内部は同じデータを指す可能性があります)。したがって、aは変更される可能性があります。ただし、oaのディープコピーである場合、aは変更されません。

参照渡しの場合:

void func2(Object& o);

そして、呼び出す

func2(a);

aを参照する新しい方法を提供するだけです。 「a」と「o」は、同じオブジェクトの2つの名前です。 func2内のoを変更すると、「a」という名前のオブジェクトを知っている呼び出し元にこれらの変更が表示されます。

8
Flame

これらのすべての入力に感謝します!

オンラインで講義ノートからその文を引用しました: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf

最初のページ6番目のスライド

"VALUEで渡す変数の値は関数に渡されます関数がその値を変更する場合、変更はその関数のスコープ内に留まります。

REFERENCEで渡す変数への参照は関数に渡されます。関数がその値を変更すると、呼び出し関数のスコープ内でも変更が表示されます。

どうもありがとうございました!

6
user36064

あなたの質問を正しく理解しているかどうかわかりません。少し不明瞭です。ただし、混乱を招く可能性があるのは次のとおりです。

  1. 参照渡しの場合、同じオブジェクトへの参照が呼び出される関数に渡されます。オブジェクトへの変更はすべて元のオブジェクトに反映されるため、呼び出し元に表示されます。

  2. 値渡しする場合、コピーコンストラクターが呼び出されます。デフォルトのコピーコンストラクターは浅いコピーのみを行うため、呼び出された関数がオブジェクトの整数を変更した場合、呼び出し元の関数からは見えませんが、関数がオブジェクト内のポインターが指すデータ構造を変更した場合、その後、これは浅いコピーのために呼び出し元に表示されます。

私はあなたの質問を誤解したかもしれませんが、とにかく突き刺すと思った。

5
vboctor

解析すると、これらの単語は間違っています。 「関数がその値を変更する場合、その変更は、参照渡しの場合は呼び出し関数のスコープ内に表示されますが、値渡しの場合は表示されません。」

2
dreeves

「関数がその値を変更する場合、その変更は値渡しと参照渡しの両方の呼び出し関数のスコープ内にも現れます」という言葉の理解は、それらがエラーであるということです。

呼び出された関数で行われた変更は、値渡しの場合、呼び出し元の関数のスコープ内でnotです。

引用された単語を間違って入力したか、間違っているように思われるコンテキストから抽出されました。

ソースを正しく引用していることを確認してください。エラーがない場合は、ソース資料でそのステートメントを囲むテキストをさらに記載してください。

1
jwpfox