- - PR -
String型の値渡し
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-08-20 18:20
こんなプログラムを書いてみました。
chgメソッドには参照情報が渡されているので、chgメソッドで値が変更された場合呼び出し元に影響するのかなとおもったのですが…。 つまりメッセージで表示されるのは2かな?と思ったのですが…。 私の考えは間違ってますでしょうか? Module Module1 Sub main() Dim s As String = "1" chg(s) MessageBox.Show(s) End Sub Private Sub chg(ByVal s As String) s = "2" End Sub End Module | ||||||||
|
投稿日時: 2005-08-20 18:28
それは、「変更している」ではなく、「参照先を変えている」では? それだと String 型だとか関係なく他の参照型も変わらないです。 --編集 もうちょっと詳しく書きます。 string a = "aiueo"; string b = a; とした場合、a と b を格納するメモリと、"aiueo"を格納するメモリができます。(a,bはスタックに、"aiueo"はヒープに) a には入る値は、"aiueo"のアドレスです。 b に入る値も、"aiueo"のアドレスです。 次に、 a = "kakikukeko"; としたら、同様に、"kakikukeko"がヒープに格納され、a には"kakikukeko"のアドレスが入ります。b は "aiueo"のアドレスが入ったまま。 上記の場合は、b = a としてますが、メソッドに値渡しするときも同じことです。 [ メッセージ編集済み 編集者: 囚人 編集日時 2005-08-20 18:35 ] [ メッセージ編集済み 編集者: 囚人 編集日時 2005-08-20 18:36 ] | ||||||||
|
投稿日時: 2005-08-20 19:41
chg メソッドの引数 s に渡されたインスタンスと、chg メソッド内の「"2"」は別のインスタンスです。 つまり、引数 s のインスタンスに対して操作をしているわけではなく、 引数 s に別のインスタンスを代入しているだけなので呼び出し元には影響は与えません。 | ||||||||
|
投稿日時: 2005-08-20 23:46
みすたーXさんの疑問は
stringは参照型なのに、ByValで渡した先で変更しても 呼び出しもとのstringが変更されない。 ということですよね。 囚人さんのおっしゃるように、stringの値を変更する場合は 格納値を変更するのではなく、参照先の変更が行われます。 一度インスタンス化されたstringの文字列が変更されることはありません。 変更は必ず、新規文字列を別に用意して、参照先をそこへ変更することで実現されます。 なので string が参照型であっても、呼び出し先で変更された時点で 呼び出し元とは異なるものを指すようになるだけで 呼び出し元の値に影響を与えません。 stringは参照型だが、値型として扱えるようになっている と思うと簡単です。 | ||||||||
|
投稿日時: 2005-08-21 00:06
横レスですが、c言語で書くとこういうことですよね?
typedef char *STRING; void chg(STRING p){ p="2"; // スタック上のポインタ変数pを変えたに過ぎない } main(){ STRING s = "1"; chg(s); } ------------------------------------- 逆に呼び出しもとに影響を与えたい場合は ByRefにすればいいことですよね? 同じくc言語で記述すると typedef char *STRING; void chg(STRING *p){ *p="2"; // ポインタがさしている参照を書き換え。 } main(){ STRING s = "1"; chg(&s); } ------------------------------------------ VB.netを持っていないのでわかりませんけど、通常はこんな挙動ですよね? 間違っていたら指摘してください。 | ||||||||
|
投稿日時: 2005-08-21 02:27
イメージ的にはこっちだと思う。
typedef char const * STRING; 俺が試したのはC#だけど似たような疑問もったな。 『C/C++的に考えて、文字列はポインタだから オブジェクトの参照渡しと同じで 呼び出しもとのオブジェクト(メモリ)を書き換えるはずなのに!』 ってね。 この方が安全なんだろうなってそのときは思った。 でも間違えてしまうよな。 | ||||||||
|
投稿日時: 2005-08-21 11:03
C++でオブジェクトのポインタを値渡しした場合、ポインタの値のコピーが渡されますが、そのコピーポインタが指してるオブジェクトは呼び出し元のオブジェクトなので、ポインタを値渡ししても渡されたポインタ経由で呼び出し元のオブジェクトの中身を変える(不注意の場合は壊す)ことができます。おそらくこの現象のことを指しているのではないでしょうか。 ところがC++もそうですが、ポインタではなくオブジェクトを値渡しした場合は、そのオブジェクトのコピーが作られ、そのコピーが呼び出し先に渡されるので、呼び出し先のコピーをいくら変更したところで呼び出し元のオブジェクトに影響を与えることはなくなります。 | ||||||||
|
投稿日時: 2005-08-21 11:47
単純に、System.Stringにはメンバを変更するメソッド/プロパティがないから変更できない、というだけだと思いますが。
例えば文字列の1文字目だけを置き換えようにもCharsプロパティ(C#のインデクサ)は読み取り専用であるとか。 直接文字列を代入したりするのは参照先そのものを変更するという事ですから値渡しの時に呼出元に影響しないのは当然ですよね。 //内部実装的にはもっと色々問題があると思いますが(変更不可にしてるのは速度を稼ぐためとか聞いたことがあるし) //取りあえずの認識として。 実のところ、System.Stringにフィールドとして存在しているm_firstCharメンバをリフレクションを利用して変更してやれば、呼出元の文字列も変更されますし。
[ メッセージ編集済み 編集者: Hongliang 編集日時 2005-08-21 12:07 ] |