Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are 'Set' and 'Dictionary' memory addresses different when deep copying is done?

Tags:

swift

I recently learned about CoW (copy-on-write). However, I have a question.

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

Both instances have the same memory address before changing the data in the array. However...

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

As far as I know, 'CoW (copy-on-write)' copies data when the value changes and shares the original resources before the value changes. In my opinion, 'Array' seems to share the same resources before the value changes. However, I wonder why 'Set' and 'Dictionary' have different memory address values when the value changes have not occurred.

(p.s. I understand that CoW is implemented internally in the 'Collection Type'.)

like image 446
홍진표 Avatar asked Feb 04 '26 15:02

홍진표


1 Answers

You should see some warnings like this if you are using Swift 5.10:

Forming 'UnsafeRawPointer' to a variable of type 'Set'; this is likely incorrect because 'Set' may contain an object reference.

This warning is added to point out this exact mistake that you are making.

Converting an Array to UnsafeRawPointer using the & prefix gets you a pointer to the internal storage of the array, but converting Sets and Dictionarys do not have the same behaviour. You just get the stack address of that var. dict and newDict are different variables, so of course their addresses are different.

I don't think there is any public APIs for getting the address of the internal storage of a Set or Dictionary. For other types like Data, there is Data.withUnsafeBytes, though.

If you want to demonstrate copy-on-write behaviour with Set and Dictionary, I would use the "Allocations" tool in Instruments.app. It will count how many instances of the dictionary/set storage are allocated. My answer here demonstrates this for Set.

like image 101
Sweeper Avatar answered Feb 06 '26 06:02

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!