忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

配列の使い方の注意点について(コピー, Clone)

前回の以下の記事は配列の使い方の基本について記しましたが、 今回は配列を使う場合の注意点をまとめてみました。

配列の使い方について(Dim, Redim)

それでは以下の内容で説明したいと思います。


■配列変数のコピー

以下のソースを見て下さい。 最初に配列「arr1」「arr2」を宣言していますが、「arr1」のみ初期化も行っています。
その後、「arr2」に「arr1」を代入しています。 (この代入で「arr2」に「arr1」の内容全てがコピーされた様に思いますが、実際にそうでしょうか。)
「arr1」の2番目の要素クリア後、「arr1」及び「arr2」の内容を全てコンソールに表示させてどうなったかを見てみます。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言
        Dim arr1() As Integer = {100, 200, 300}     'こちらは配列初期化有り
        Dim arr2() As Integer                       '配列宣言のみ

        '配列変数のコピー
        arr2 = arr1

        '「arr1」の2番目の要素クリア
        arr1(1) = 0

        '「arr1」の内容表示
        For i As Integer = 0 To UBound(arr1)
            Console.WriteLine("arr1[{0}]:{1}", i, arr1(i))
        Next
        '「arr2」の内容表示
        For i As Integer = 0 To UBound(arr2)
            Console.WriteLine("arr2[{0}]:{1}", i, arr2(i))
        Next
    End Sub

実行結果がコンソールには以下様に表示されます。

arr1[0]:100
arr1[1]:0
arr1[2]:300
arr2[0]:100
arr2[1]:0
arr2[2]:300

予想に反して「arr1」及び「arr2」共に同じ値が表示されました。
どうしてこうなるのかと言いますと、「配列変数のコピー」では配列の中身では無く参照をコピーすることになるからです。 参照とは配列の実体を指し示すポインタと言った方がいいかもしれません。

実は変数「arr1」も配列の実体の参照でしかないということです。 {100, 200, 300} と宣言された配列の実体はどこかにあり、その実体を指し示すポインタを変数「arr1」が保持しています。

実体をコピーしたい場合には配列の Clone メソッドを使います。以下にその様子を示します。

■配列変数の実体コピー(Clone)

上記のソースでは配列変数コピーで単に変数同士のコピーを行いましたが、 以下では配列の Clone メソッドの結果を代入しています。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言
        Dim arr1() As Integer = {100, 200, 300}     'こちらは配列初期化有り
        Dim arr2() As Integer                       '配列宣言のみ

        '配列変数の実体コピー
        arr2 = arr1.Clone

        '「arr1」の2番目の要素クリア
        arr1(1) = 0

        '「arr1」の内容表示
        For i As Integer = 0 To UBound(arr1)
            Console.WriteLine("arr1[{0}]:{1}", i, arr1(i))
        Next
        '「arr2」の内容表示
        For i As Integer = 0 To UBound(arr2)
            Console.WriteLine("arr2[{0}]:{1}", i, arr2(i))
        Next
    End Sub

実行結果がコンソールには以下様に表示されます。

arr1[0]:100
arr1[1]:0
arr1[2]:300
arr2[0]:100
arr2[1]:200
arr2[2]:300

結果を見れば指標「1」の要素が「arr1」及び「arr2」が異なる値であることが分かります。

Clone メソッドは配列の実体を別に作成し、全ての要素をコピーしその参照を返します。 (Clone 直後は要素の内容は全て同じです。) そのため、「arr1」及び「arr2」は実体が別々の配列となります。


■配列の実体コピー・ディープコピー(Serializable)

以下の記事にもありますが、配列も1個のオブジェクトなので配列の実体をシリアル化して、別の実体にシリアル化を戻せば、 配列のコピーができることになります。

各種オブジェクトのコピーができるディープコピー(BinaryFormatter,MemoryStream,Serialize,Deserialize)

以下のソースに上記の記事内の関数を利用して配列のコピーを行います。

    Private Sub btnArray_Click(sender As Object, e As EventArgs) Handles btnArray.Click
        '配列宣言
        Dim arr1() As Integer = {100, 200, 300}     'こちらは配列初期化有り
        Dim arr2() As Integer                       '配列宣言のみ

        '配列の実体コピー・ディープコピー
        arr2 = DeepCopy(arr1)

        '「arr1」の2番目の要素クリア
        arr1(1) = 0

        '「arr1」の内容表示
        For i As Integer = 0 To UBound(arr1)
            Console.WriteLine("arr1[{0}]:{1}", i, arr1(i))
        Next
        '「arr2」の内容表示
        For i As Integer = 0 To UBound(arr2)
            Console.WriteLine("arr2[{0}]:{1}", i, arr2(i))
        Next
    End Sub

実行結果がコンソールには以下様に表示されます。

arr1[0]:100
arr1[1]:0
arr1[2]:300
arr2[0]:100
arr2[1]:200
arr2[2]:300

関連する記事

配列の使い方について(Dim, Redim)
配列の範囲指定によるコピー(Array.Copy, Skip, Take)











PR

コメント

コメントを書く