質問するログイン新規登録

Q&A

5回答

2511閲覧

「広義の参照渡し」とは何か?

raccy

総合スコア21840

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

2グッド

4クリップ

投稿2019/05/18 22:38

編集2019/05/19 14:08

2

4

C++、C#、PHP、VB.NET、Delphi(Object Pascal)、Swift、Rust等には「参照渡し」と言われる機能があります。

どれらも、英語では"pass by reference"という表現をしており、Microsoftやembarcaderoは「参照渡し」、PHP日本語訳チームは「リファレンス渡し」と訳しています。C++については、仕様書にそのまま"pass by reference"という言葉の解説はみつけられませんでしたが、n4659のp.855などで"~ be passed by reference"という表現が使われています。

上記のような言語では、"pass by reference"(英語圏では"call by reference"とも言われる場合がある)と言われる機能があります。私が解釈する限り、これらの機能は同一のものです。そして、その日本語訳として「参照渡し」というのは特におかしくないと思います。

さて、私が聞きたいのは、言語の機能として「参照渡し("pass by reference")」がある場合の話ではありません。言語の機能として「参照渡し」がない、少なくとも、英語の公式ドキュメントで"pass by reference"がない言語、ましてや、Pythonのように値渡しであると公式ドキュメントに書いてある言語において、「参照渡し」が意味する物が何であるのかと言うことです。これらを一部の人達は広義の意味での「参照渡し」と言っているようですので、以下、この質問では「広義の参照渡し」とし、前述のC++等での機能を「狭義の参照渡し」とします。(そういう言葉があるわけではありませんので、ご注意ください。この質問でのみの表現です。)つまり、聞きたいこと事は端的に言うと以下になります。

「広義の参照渡し」の定義は何ですか?

また、その定義から、C、Java、JavaScript、Python、Ruby、Groovy、Go、Haskell、Scala、Kotlin、R、Lua等の「狭義の参照渡し」が無い言語において「広義の参照渡し」とは具体的にどのような動作のことを指すのかの説明も加えていただければ幸いです。逆に「広義の参照渡し」すらない言語はどのような物があるのかも教えて頂くと助かります。

なお、回答では「広義の参照渡し」と「狭義の参照渡し」を区別していただくようお願いします。「区別することが不可能である」と考えているのであれば、単に「参照渡し」と書いても良いですが、その場合は、「区別することが不可能である」理由も添えて頂くと助かります。

「狭義の参照渡し」がある言語やない言語のリストは、私も全ての言語に詳しいわけではありませんので、間違いがあるかも知れません。また、この言語も足して欲しいという場合もあると思います。その場合は、追記・修正依頼で指摘して頂くと助かります。


不公平感が出ないように、私の考えの立場を言っておきます。私は「『狭義の参照渡し』と混合するから『広義の参照渡しは』使うべきではない」と考えています。ただ、この考えを全ての人に押しつける気はなく、C++等を学ぶことが生涯ない人は別にそれでいいのではないかと思っています。「広義の参照渡し」の事例は集めていますが、私自身「広義の参照渡し」なるものの使用を前述の理由で避けていたため、どのような場合に使われる事が多いことを知っていても、その定義がどのようなものか、どのような場合に使うべきかまでは考察したことがありません。そのため、既にそれらに確固たる信念をもって使用されている方にお聞きすべく、この質問をすることにしました。

この質問で、別に「広義の参照渡し」を使うなと言っているわけではありません。どのような意味で「広義の参照渡し」を使っているのかを知りたいという純粋なる知識欲から質問しています。

juner, LouiS0616👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

退会済みユーザー

退会済みユーザー

2019/05/18 22:51

飽きないでちゅか?
raccy

2019/05/18 23:42

飽きない理由を追記しました。
退会済みユーザー

退会済みユーザー

2019/05/18 23:51

うーんと、この論争をちて、誰が得をするのかなぁ?って疑問なのでちゅ。 勉強熱心な事はすばらちいとおもうのでちゅが、 こんな論争をちても、社会の問題は何も解決ちないと思うのでちゅね。 ぎじゅつしゃの知的好奇心なのはわかるのでちゅが、 これが白黒ついたからといって何かあたらちい発想が生まれてくるとも、 到底思えないのでちゅよねぇ…。
xebme

2019/05/19 01:15

URLが広義の参照であるか?勝手にGCされるけど。遊びの範囲を拡げると面白くなる可能性はあります。
退会済みユーザー

退会済みユーザー

2019/05/19 01:28

>面白くなる可能性はあります。 だからあなた達は、「オタクキモーい」って言われるんだと思いまちゅ。
otn

2019/05/19 09:10 編集

「raccy 2019/05/19 09:16」 のコメントを見ましたが、私も質問を見てnskydivingさんと同じ誤解をしました。私が「"広義の参照渡し"」でググると5件でした。ネット上にほとんど無い表現を使わないようにしようという意見は無意味だなと思いました。 「ポインター(やリファレンス)の値渡しのことを、参照渡しと表現することを止めよう」 ということであれば、そう書いた方が良いです。 少なくとも、あなたの文脈なら、 > 「広義の参照渡し」 じゃなくて、 > 広義の「参照渡し」 と書いた方が良い。
Zuishin

2019/05/19 13:11 編集

「広義の参照渡し」というカッコの使い方については [C言語での値渡しと参照渡しの使い分けについて](https://teratail.com/questions/189570#reply-281419) のコメント欄における私の書いたものが出典のようです。 その更なる出典は HogeAnimalLover さんの発言でしたが、そこから先の出典については何度お尋ねしても、明確に示されませんでした。最後に漏らされた言葉によると、どうやら「宗教」ということのようです。
raccy

2019/05/19 14:02

「広義の参照渡し」と「狭義の参照渡し」と表現しているのは、そのまま"参照渡し"と書かれてしまうと、回答者がどちらの意味で言っているのかがわからなくなるため、わざわざ「」で強調、かつ、分離できないように「」内に含める形にしています。この質問において明確に区別するための表現ですので、一般的にそのような表現があると考えているわけではありません。もちろん、「区別できない」と言う考えもあり得ると想定しており、その場合は、その旨と理由を書いて欲しいとしています。
raccy

2019/05/19 14:23

なお、言葉選びで先のZuishinさんがはったURL先のコメントのやり取りを参考にしています。別に「参照渡しA」と「参照渡しB」としてもよかったのですが、そちらの方が、下手に混乱を招かずに良かったのでしょうかね。
otn

2019/05/19 15:02

「」は強調とは違うので、強調したいなら、マークダウンでBoldにした方が誤解がなかったでです。 コメント欄だとマークダウンが使えないので、**広義の参照渡し** とか。
raccy

2019/05/19 21:44

すいません、上の文で、「わざわざ『』で強調」のところの強調は、地の文との区別を強調したいという意味です。その言葉を強調したいという意味ではありません。字足らず過ぎて申し訳ないです。
guest

回答5

0

Pythonのように値渡しであると公式ドキュメントに書いてある言語において、「参照渡し」が意味する物が何であるのかと言うことです。

pythonでいうと、「オブジェクトの値そのもの」を変数として持つ方法がなく、かならず参照(インスタンスへのポインタというか)を持つ形になります。そのため、

引数は 値渡し (call by value) で関数に渡されることになります (ここでの 値 (value) とは常にオブジェクトへの 参照(reference) をいい、オブジェクトの値そのものではありません) [1]

注として、

[1] 実際には、オブジェクトへの参照渡し (call by object reference) と書けばよいのかもしれません。というのは、変更可能なオブジェクトが渡されると、関数の呼び出し側は、呼び出された側の関数がオブジェクトに行ったどんな変更 (例えばリストに挿入された要素) にも出くわすことになるからです。

となります。

なのでむしろ、「参照渡ししかない」という言い方をしているドキュメントを呼んだことがあった気がします。

「変更可能なオブジェクトが渡されると、関数の呼び出し側は、呼び出された側の関数がオブジェクトに行ったどんな変更 (例えばリストに挿入された要素) にも出くわす」という書き方は面白く、つまり、引数のオブジェクトに対する副作用が発生しうる渡し方と、値のコピーを受け取る(副作用が起きない)渡し方があるという捉え方があるといえます。

また、その定義から、C、Java、JavaScript、Python、Ruby、Groovy、Go、Haskell、Scala、Kotlin、R、Lua等の「狭義の参照渡し」が無い言語において「広義の参照渡し」とは具体的にどのような動作のことを指すのかの説明も加えていただければ幸いです。逆に「広義の参照渡し」すらない言語はどのような物があるのかも教えて頂くと助かります。

なので、「引数として渡したオブジェクトに対する副作用を起こしうる渡し方」を「広義の参照渡し」と自分なら呼ぶかもしれないです。

Pythonはすべて「広義の参照渡し」ですし、JavaScriptもプリミティブ型を除き同様の振る舞いです。

投稿2019/05/20 09:32

otolab

総合スコア767

raccy

2019/05/20 10:46

なるほど「副作用を起こしうる」が基準になると言うことですか。そうなると、Pythonの`int`や`str`等のイミュータブルなオブジェクトの場合は、「副作用を起こしうる」ことは無いので「広義の参照渡し」にはならないとなるといったところでしょうか?JavaScriptのプリミティブ型もイミュータブルですので、「広義の参照渡し」にはならないのと同じような感じにです。 しかし、この視点はなかったです。C++で`int f(const std::vector& v)`なんて書いた場合、「狭義の参照渡し」のひとつですが、`const`修飾子によって「副作用を起こしうる」ことは無いので「広義の参照渡し」にはならないとなるとなるのですね。「狭義の参照渡し」はすべて「広義の参照渡し」に入ると思って、狭義・広義の言葉を使いますが、失敗だったようです。もっと良い表現を誰か提案いてくれると助かります。「参照渡しA」や「参照渡しB」では味気ないですので。 そういえば、「オブジェクトへの参照渡し (call by object reference) 」ですが、「オブジェクトへの」と「参照渡し」は分離して考えらえると言うことでいいでしょうか?英語では不可分に見えますが。
otolab

2019/05/20 12:01

> なるほど「副作用を起こしうる」が基準になると言うことですか。そうなると、Pythonの`int`や`str`等のイミュータブルなオブジェクトの場合は、「副作用を起こしうる」ことは無いので「広義の参照渡し」にはならないとなるといったところでしょうか?JavaScriptのプリミティブ型もイミュータブルですので、「広義の参照渡し」にはならないのと同じような感じにです。 そういうイメージです。 > C++で`int f(const std::vector& v)`なんて書いた場合、「狭義の参照渡し」のひとつですが、`const`修飾子によって「副作用を起こしうる」ことは無いので「広義の参照渡し」にはならないとなるとなるのですね。 むむ、それは参照渡しですね...。適当言ってしまった。 ただ最終的に同じインスタンスにアクセスしている状態であれば(read / write何れにせよ)、それは参照渡しなのだと思います。 > そういえば、「オブジェクトへの参照渡し (call by object reference) 」ですが、「オブジェクトへの」と「参照渡し」は分離して考えらえると言うことでいいでしょうか?英語では不可分に見えますが。 pythonの場合、「プリミティブ型の値渡ししかない」かつ「プリミティブ型としてオブジェクトへの参照型がある(オブジェクトの実体は変数にならない)」という仕様だったはずです。 なので、 「プリミティブ型の値渡ししかない」「オブジェクトは参照渡しである」が両立する感じですね。 「参照型以外のプリミティブ型を例外として、全て参照渡し」という言い方もできるわけです。
guest

0

pass by value/reference の by は「~によって」、「~を使って」という意味で、何を渡すかは書いてないですよね。

  • pass by hand: 手で渡す(何を?)
  • go by bicycle: 自転車で行く(どこへ?)

昔の言語は「値型変数」(保持値=代入値)しかなくて、値型変数を値渡しするか参照渡しするかでした。

  • 1.変数の値を渡す:値型変数の値渡し(実引数と仮引数は別変数、値コピー)
  • 2.変数自体を渡す:値型変数の参照渡し(実引数と仮引数は同一変数、変数共有)

その2つの pass by value/reference を省略せずに書くと、

  • pass the assigned value by holding value of the variable (変数の保持値によって代入値を渡す)
  • pass the variable by reference to it (変数への参照によって変数自体を渡す)

といった文になるんじゃないかと想像します。
そのあと、変数の保持値として値そのものではなく値への参照を保持する「参照型変数」(保持値≠代入値)が登場して、(C++の参照型変数は定義が違う別物です)

  • 3.参照型変数の値渡し(実引数と仮引数は別変数、オブジェクト共有)
  • 4.参照型変数の参照渡し(実引数と仮引数は同一変数、変数共有)

が増えることになりました。
Pythonは「参照型変数」しかなくて「値渡し」しかできないので3.のみできます。
3.を英語にすると pass the reference to the object とか pass the object by object reference でしょうか。「オブジェクト共有渡し」とか単に「共有渡し」と呼ばれています。

ということで、1.と3.が「狭義の値渡し」で2.と4.が「狭義の参照渡し」、1.が「広義の値渡し」で3.が「広義の参照渡し」ということになるかと思います。ただし、C言語の「ポインタ型変数の値渡し」は1.なのですが「広義の参照渡し」になると思います。
要するに「呼出し元に影響を与えない」のが「広義の値渡し」、「呼出し元に影響を与える」のが「広義の参照渡し」かと思います。

Qiitaに図解記事を書いてみました。参考になりましたら幸いです。

投稿2025/11/29 01:52

編集2025/11/29 22:21
shiracamus

総合スコア5413

0

Swift の inout の場合は「参照渡し」の語は概念の説明に使うことが多く, 実際の呼称としては inout 渡しとか in-out 渡しという「見たまんま」の呼び方のほうが多い気がします.

自分自身は C++ や C# を扱った経験があるため, 広義の参照渡しのほうの意味で「参照渡し」という語を用いることはあまりありませんが, 自分が今まで見てきた広義の参照渡しの事例の共通項を探ると:

  • 「それ自身の値は意味を持たず, 何らかの値を参照するための値」を「渡す」.

という感じかなと思います.
前者は名前通りの「参照」という語のこともありますし, C言語などであれば「アドレス」が相当します.

ここからは推測になってしまいますが, 多くの「広義の参照渡し」事例のルーツとなっていると思われるのは現在主流の多くの言語の源流となった, C言語ではないでしょうか.

(C++ でない, 純粋な) C言語には狭義の参照渡しが存在しないため, 狭義の参照渡しで実現したいような処理はアドレスを渡して代替するほかありません.

すると「こういうこと (参照渡しが必要になりそうなこと) がしたい」 -> 「やりたいことはプログラミング一般で言えば参照渡しと呼ばれる概念を使えばいいが, C言語には直接それに相当する機能はないため, こう実装する」 -> 「参照渡しはC言語ではこう実装する」 -> 「C言語ではこれが参照渡し」みたいな誤解に繋がったのではないかと.

また, 純C言語は:

  • 大きなデータ構造を作ることはできるが, それを単に渡すと (最適化にも依るが) コピーが走ってしまう.
  • 戻り値はひとつだけ.
  • 例外など「戻り値以外で外部へエラーを戻す手段」がないため 「欲しい値」か「エラー情報」のどちらかをダブルポインタを使って得たい場面が多い. (それ以外だと, グローバル変数や別の関数からエラー情報を得るなんて実装が普通にありますが, 当然副作用など注意が必要)
  • 文字列などの非常によく使われるデータ構造をはじめ, 標準ライブラリの多くの関数もアドレスの存在を前提として設計されている.

などの理由で, あまり用語を知らない初心者でもアドレスを渡す場面が多いため誤解を促進しやすい環境と言えます.

そして知名度の高い言語で誤解のある状態で, 「参照」という概念のある言語が広まるのが追い討ちになります.
C言語で上記のまま覚えた人は, その言語で同じことを実現するために「参照」という値を「渡す」ことを「参照渡し」と呼び始めます.
するとC言語を知らない方は「参照」を「渡す」から「参照渡し」かあ, と一層誤解を広めてしまいます.

...という感じではないかなぁ, と推測します.

投稿2019/05/28 07:35

kagilinn

総合スコア354

kagilinn

2019/05/28 07:42

「Swift の inout の場合は「参照渡し」の語は概念の説明に使うことが多く, 実際の呼称としては inout 渡しとか in-out 渡しという「見たまんま」の呼び方のほうが多い気がします」 について, ちょっと自分でも誤解があったかも知れません. ただ Swift でも「参照渡し」を「参照という値」を「渡す」意味で使っている事例があったりするので, 「Swift で参照渡しは inout」と表現してもやはり誤解される恐れがあるということは補足しておきます.
raccy

2019/05/28 09:48

結局の所「広義の参照渡し」は誤解であるという所なのでしょうか?C++等を知れば、いつかは誤解が解けて、言わなくなるはずと言ったところでしょうか…。 うーん、これまで多くの「広義の参照渡し」を使っている人を見てきましたが、C++の「狭義の参照渡し」をいくら説明しても、彼らは「広義の参照渡し」を使い続けていましたので、誤解等から来ていない、何かもっと信念みたいな事があるに違いないと期待しているんですがね。
kagilinn

2019/05/28 10:06 編集

だとすれば「広義の参照渡し」とは, 「渡し方そのもの」「渡す手段」ではなく, 「考え方」というか, 「そうする目的」というか, そういう何かを指すのだと思います. レイヤが違っているというか. つまり, どんな手段を使ったとしても: * 呼ばれた側に, 呼び出し側が持っているデータを変更したり間接参照をさせるという考え方 * 呼ばれた側から, 呼び出し側が持っているデータを変更または間接参照したい, という目的 で引数を使うのであれば, それは「広義の参照渡し」なのではないでしょうか.
kagilinn

2019/05/28 10:16 編集

例えば, 古い処理系で「データを変更させるには, グローバル変数として置いた配列を使うしかない」とすれば, サブルーチン側で配列を参照・変更できるようインデックスを渡すのも「広義の参照渡し」なのでは.
guest

0

広義の参照渡し」で Google 検索しましたが、10 件しかヒットしませんでした。

「広義の参照渡し」は一般的な用語ではなく、その文脈の中だけで使われた言葉だと思われます。

ですので、

「広義の参照渡し」とは何か?

という問いに対しては、その言葉を使った人に聞いてみないと分からないと思います。

おそらくですが、
「引数の値を間接的に読み取りおよび書き込みが可能な機能」
または
「狭義の参照渡しを代替えする機能」
みたいな意味合いで使っているのではないかと思います。

投稿2019/05/19 00:00

nskydiving

総合スコア6500

raccy

2019/05/19 00:16

質問文がちょっと悪かったようですので、ちょっと修正しています。この質問で言っている「広義の参照渡し」というのは"広義の参照渡し"と表現される事柄のことではありません。最初に述べた機能としての「参照渡し」以外に対して「参照渡し」と使っている、曰く、広義の意味での「参照渡し」のことを、機能としての「参照渡し」と区別するために「広義の参照渡し」としています。わかりにくくて申し訳ありません。 nskydivingさんも使ったことがないのですよね?そうなるとどうしても推測の域をでないですよね。渡しもなんとなくそんなかんじじゃないかなというのはわかりますが、なんとなくじゃない回答が欲しいところです。
nskydiving

2019/05/19 01:26

私自身は「広義の参照渡し」という言葉は使ったことありません。 しかし、「広義の〇〇」という日本語表現には「厳密な意味ではなく」という意味合いがあると思うので「なんとなくじゃない回答が欲しい」というのはちょっと難しい気がしますね。
cateye

2019/05/19 01:58

#アセンブラで言えばレジスタ(orスタック)に乗ってるのが、データなのかアドレスなのかの違いだけなんだけどなぁ・・・
guest

0

参照渡しとは左辺値または右辺値を参照として渡す手続きです

void left(int &), //左辺値参照 right(int &&); //右辺値参照

この時参照を受け取る引数(変数)を参照変数と呼びます
代表的な例では、変数は左辺値を返し、式は右辺値を返します

狭義の参照渡し

ここでは前述の二つの手続きのうちいずれかを言語仕様として採用するケースを指します
例えばC#ではref/outが左辺値参照、inが左辺値及び右辺値参照の両方をサポートします

class Value{ void Left(ref int x,out int y); void LeftAndRight(in int x); void Example(int x){ Left(ref x,out int y); //左辺値 LeftAndRight(in x); //左辺値 LeftAndRight(x+x); //右辺値 } }

PHPでは左辺値参照のみをサポートします

<?php function left(&$x){ echo $x; } $x=0; left($x); //左辺値 ?>

多くの言語で参照渡しと表現する場合、その実装は後者の左辺値参照のみを指します

広義の参照渡し

ここまで紹介した参照渡しの基礎を狭義の参照渡しと分類する場合、それ以外の全ての参照手続きが広義の参照渡しです
これらは便宜的に参照値渡し共有渡しなどと呼称されます

  • ポインタ

参照渡しを含め、全ての参照手続きの土台となる機能がC言語のポインタです
これは参照の最も基本的な操作です

int *pointer(int *x); int x=0,*y=pointer(&x);

ポインタは右辺値として解釈されます
一方で、ポインタの参照を外して得られる値は左辺値です

int &right(void){ return *new int; //左辺値 };

この性質の違いにより、ポインタによる参照を参照渡しと同列に扱うことはできません
ポインタによる参照が右辺値を介する参照であるため、ポインタを渡す操作そのものは”ポインタと呼ばれる右辺値の複製”であり、値渡しとなります

  • ハンドラ

C++/CLIにはハンドラと呼ばれるポインタの類似構文があります

object ^x=gcnew object();

これは.Netをサポートするための拡張で、オブジェクトの参照を扱うための演算子です
Javaをはじめとした多くのクラス指向言語が採用する参照機構をベースとしています
これらはポインタを抽象化し、GC(ガページコレクション)で管理されるオブジェクトのアドレスを捕捉する目的でサポートされます

class Program{ public void main(){ Object instance=new Object(); //右辺値 } }

変数に格納する値がアドレスであるため、ポインタと同様に右辺値の一種です
C#ではunsafeを用いてこれを確認できます

unsafe{ object o=new(); object *p=&o; }

GCのサポート下にあるため、右辺値としてはポインタと差別化されます
そのためインスタンス変数が扱うオブジェクトのアドレスは参照値と呼ばれます
右辺値であるため、これを渡す手続きはポインタと同様に値渡しとなります

「広義の参照渡し」の使用場面

狭義の参照渡し広義の参照渡しは、関数に渡す値が「左辺値もしくは右辺値の参照」か「右辺値そのもの」かで相違します
一方で狭義とは広義を厳密に整理した定義であるため、これは参照という概念を拡張するための便宜でもあります
つまり双方の違いを「区別させないため」の方便なので、これ自体を参照という概念の抽象化と捉えることもできます
初心者に向けた解説の導入として、あるいは参照の種類を問わず、その概念を研究対象とする場合においては有用であると言えるでしょう

投稿2025/11/29 21:37

編集2025/11/29 23:04
nanashi123

総合スコア165

nanashi123

2025/11/29 22:53 編集

> 「区別することが不可能である」理由 「広義」という言葉の意味を踏まえれば、詰まるところは「区別してはならない文脈」であることが前提となります 区別ができないではなく「その必要がない」と解釈するのが妥当でしょう 参照の種類は本回答の二種類に限定されますが、実装面では汎用性を考慮しても •ポインタ •参照渡し •インスタンス参照 •所有権 の4つがあり、同じ参照型でも •イミュータブル(非破壊) •ミュータブル(破壊的) の二種類に分かれます 更に細分化すれば、オブジェクトの参照をリレーする一意型、破壊的変更を表現するSTモナドなど、そのスタイルは多岐に渡ります こうした言語毎の差異を吸収し、その目的にのみ焦点を当てれば、重要なのは運用面での解釈です •「破壊的」な操作には参照を使う •「非破壊」な管理では複製を行う 非破壊的なデータに対し、値型と参照型の分類を問う意味は薄く、破壊的なデータに対し、非破壊的なデータ構造の知見は必要性を伴わない よって実装を理解する上では詳細な知見がノイズになる側面が大きく、とは言え語弊に対する注釈は必須になる そこで「広義」が要請されます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問