Путаница с мелкими копиями массивов в Visual Basic - PullRequest
0 голосов
/ 31 января 2019

Насколько я понимаю, поверхностная копия массива копирует переменную массива, поэтому у вас есть два указателя на одну и ту же область памяти в куче.Но в соответствии с этой логикой должен работать следующий фрагмент кода, но он этого не делает:

Sub Main()
    Dim row As Long() = {1, 2, 3, 4}
    ChangeRow(row.Clone)
    Console.WriteLine(row(0))
End Sub

Sub ChangeRow(ByVal array As Long())
    array(0) = 0
End Sub

Предположительно, метод Clone делает поверхностную копию.Это будет означать, что вы передаете указатель на исходный массив в качестве параметра.Все, что я прочитал по этой теме, указывает на то, что этот кусок кода работает, но это не так.Кто-нибудь может объяснить?

Рассматриваемый диалект VB.Net

1 Ответ

0 голосов
/ 31 января 2019

Насколько я понимаю, поверхностная копия массива копирует переменную массива, поэтому у вас есть два указателя на одну и ту же область памяти в куче.

Нет.Он создает новый контейнер, содержащий все те же элементы и в остальном идентичный предыдущему контейнеру, но сами контейнеры находятся в разных местах в куче.Он не создает дублирующую ссылку на предыдущий контейнер.

То, что вы описываете, является просто ссылкой.Рассмотрим этот код:

Dim row As Long() = {1, 2, 3, 4}
Dim otherRow as Long() = row

Память программы теперь выглядит примерно так:

reference

Clone действительно создаст поверхностную копию, то есть он создаст новый массив, который содержит все те же значения, что и исходный массив.Затем вы устанавливаете значение для первого элемента в этом новом массиве, но это не повлияет на оригинал, потому что это совершенно разные массивы без ссылок друг на друга во время выполнения.Рассмотрим этот код:

Dim row As Long() = {1, 2, 3, 4}
Dim otherRow as Long() = row.Clone

Память программы теперь выглядит примерно так:

clone

Если вы хотите изменитьИсходный массив в подпрограмме ChangeRow, просто не вызывайте клон.

Sub Main()
    Dim row As Long() = {1, 2, 3, 4}
    ChangeRow(row)
    Console.WriteLine(row(0)) ' outputs 0
End Sub

Sub ChangeRow(ByVal array As Long())
    array(0) = 0
End Sub

Чтобы проиллюстрировать, почему это на самом деле «мелкая» копия, посмотрите, как это работает с ссылочными типами.

Class Ref
    Public Value As Long 
    Public Sub New(ByVal value As Long)
        Value = value
    End Sub
End Class

Sub Main()
    Dim row As Ref() = {New Ref(1), New Ref(2), New Ref(3), New Ref(4)}
    ChangeRow(row.Clone)
    Console.WriteLine(row(0).Value) ' outputs 0
End Sub

Sub ChangeRow(ByVal array As Ref())
    array(0).Value = 0
End Sub

Даже если row и row.Clone относятся к разным массивам, значения в этих массивах (экземпляры Ref) одинаковы, поэтому изменение array(0).Value аналогично изменению row(0).Value.В этом случае память программы выглядит примерно так:

shallow copy

...