Search code examples
swiftswift3unsafemutablepointer

How to get an UnsafeMutableBufferPointer<Character> from array of Character


I am trying to get an UnsafeMutableBufferPointer using the following code it works sometimes in Playground and it fails also

let array : [Character] = ....
func getUnsafeMP(array: [Character]) -> UnsafeMutableBufferPointer<Character> {

    let count = array.count
    let memory = UnsafeMutablePointer<Character>(allocatingCapacity: count)

    for (index , value) in array.enumerated() {

        memory[index] = value //it fails here EXC_BAD_ACCESS
    }

    let buffer = UnsafeMutableBufferPointer(start: memory, count: count)

    return buffer
}

Solution

  • Memory addressed by UnsafeMutablePointer can be in one of three states:

    /// - Memory is not allocated (for example, pointer is null, or memory has
    ///   been deallocated previously).
    ///
    /// - Memory is allocated, but value has not been initialized.
    ///
    /// - Memory is allocated and value is initialised.
    

    The call

    let memory = UnsafeMutablePointer<Character>(allocatingCapacity: count)
    

    allocates memory, but does not initialize it:

    /// Allocate and point at uninitialized aligned memory for `count`
    /// instances of `Pointee`.
    ///
    /// - Postcondition: The pointee is allocated, but not initialized.
    public init(allocatingCapacity count: Int)
    

    On the other hand, the subscripting methods require that the pointee is initialized:

    /// Access the pointee at `self + i`.
    ///
    /// - Precondition: the pointee at `self + i` is initialized.
    public subscript(i: Int) -> Pointee { get nonmutating set }
    

    As a consequence, your code crashes inside _swift_release_.

    To initialize the allocated memory from the (character) array, you can use

    memory.initializeFrom(array)
    

    Of course you must de-initialize and deallocate the memory eventually.


    A different approach is

    var cArray: [Character] = ["A", "B", "C"]
    cArray.withUnsafeMutableBufferPointer { bufPtr  in
        // ...
    }
    

    Here no new memory is allocated, but the closure is called with a pointer to the arrays contiguous storage. This buffer pointer is only valid inside the closure.