Home > OS >  deinitialize() vs deallocate()
deinitialize() vs deallocate()

Time:01-03

Why does the below code require me to manually use unsafe_pointer.deinitialize(count: 1) to deinitialize the instance?

The instance would be still alive within my memory if I only use the unsafe_pointer.deallocate(). What is the purpose of using deallocate() then?

Sorry in advance because I'm trying to learn MRC for the first time.

class Unsafe_Memory {
  var name = "Hello World"
  deinit {
    print("\(type(of: self)) is deinited and deallocated")
  }
}

let unsafe_pointer: UnsafeMutablePointer<Unsafe_Memory> = .allocate(capacity: 1)

unsafe_pointer.pointee = Unsafe_Memory()
dump(unsafe_pointer.pointee)

unsafe_pointer.pointee.name = "Changed"
dump(unsafe_pointer.pointee)

unsafe_pointer.deinitialize(count: 1)
unsafe_pointer.deallocate()

CodePudding user response:

You have to call deinitialize on any non-trivial types. According to the Apple Docs,

A trivial type can be copied bit for bit with no indirection or reference-counting operations. Generally, native Swift types that do not contain strong or weak references or other forms of indirection are trivial, as are imported C structs and enums. Copying memory that contains values of nontrivial types can only be done safely with a typed pointer. Copying bytes directly from nontrivial, in-memory values does not produce valid copies and can only be done by calling a C API, such as memmove().

Calling deinitialize first uninitializes that memory, but as the docs state, "After calling deinitialize(count:), the memory is uninitialized, but still bound to the Pointee type".

After that, you free up that memory block by calling deallocate(), similar to free() from C. deallocate() can only be called on nontrivial types or uninitialized memory blocks.

If the type is trivial, you do not have to call deinitialize. It might be good to call deinitialize anyway in case somehow your type turns nontrivial in the future, and it does should not cost you anything to call it.

You can try by running your code without calling deallocate. The deinit block will still be executed, as deinitialize will run that block. However, that memory block is still occupied and not freed up until you call deallocate.

  • Related