Недавно я узнал о CoW (копирование при записи). Однако у меня есть вопрос.
func address(of object: UnsafeRawPointer) -> String {
let address: Int = Int(bitPattern: object)
return String(format: "%p", address)
}
var arr: Array<Int> = [1, 2, 3]
var newArr: Array<Int> = arr
print("Addr of `arr`: \(address(of: &arr))") // 0x600002e601e0
print("Addr of `newArr`: \(address(of: &newArr))") // 0x600002e601e0
Оба экземпляра имеют один и тот же адрес памяти до изменения данных в массиве. Однако...
var setValue: Set<Int> = [1, 3, 5]
var newSetValue: Set<Int> = setValue
var dict: Dictionary<String, Int> = ["zero": 0, "one": 1]
var newDict: Dictionary<String, Int> = dict
print("Addr of `setValue`: \(address(of: &setValue))") // 0x10000c098
print("Addr of `newSetValue`: \(address(of: &newSetValue))") // 0x10000c0a0
print()
print("Addr of `dict`: \(address(of: &dict))") // 0x10000c0a8
print("Addr of `newDict`: \(address(of: &newDict))") // 0x10000c0b0
Насколько мне известно, «CoW (копирование при записи)» копирует данные при изменении значения и разделяет исходные ресурсы до изменения значения. По моему мнению, «Массив», похоже, использует одни и те же ресурсы до изменения значения. Однако мне интересно, почему «Set» и «Dictionary» имеют разные значения адреса памяти, если изменений значений не произошло.
(p.s. Я понимаю, что CoW реализован внутри «Типа коллекции».)





Если вы используете Swift 5.10, вы должны увидеть такие предупреждения:
Формирование UnsafeRawPointer для переменной типа Set; скорее всего, это неверно, поскольку «Set» может содержать ссылку на объект.
Это предупреждение добавлено, чтобы указать именно на ту ошибку, которую вы совершаете.
Преобразование Array в UnsafeRawPointer с использованием префикса & дает вам указатель на внутреннюю память массива, но преобразование Set и Dictionary не имеет одинакового поведения. Вы просто получаете адрес стека этого var. dict и newDict — разные переменные, поэтому, конечно, их адреса разные.
Я не думаю, что существует какой-либо общедоступный API для получения адреса внутреннего хранилища Set или Dictionary. Однако для других типов, таких как Data, есть Data.withUnsafeBytes.
Если вы хотите продемонстрировать поведение копирования при записи с помощью Set и Dictionary, я бы использовал инструмент «Распределения» в Instruments.app. Он будет подсчитывать, сколько экземпляров хранилища словаря/набора выделено. Мой ответ здесь демонстрирует это для Set.