1

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
}
Bobj-C
  • 5,276
  • 9
  • 47
  • 83
  • "I am trying to get UnsafeMutableBufferPointer" Can you explain why? It might help to know what you are _really_ trying to accomplish. – matt Jul 10 '16 at 15:26
  • @matt I am playing with swift I want to compare looping using `UnsafeMutableBufferPointer` and the simple `for in enumeration` – Bobj-C Jul 10 '16 at 15:28
  • @matt do you have any idea how to achieve that ? – Bobj-C Jul 10 '16 at 15:33
  • But what do you want to compare? An array is _not_ an unsafe mutable buffer pointer, so you would be comparing apples and oranges. – matt Jul 10 '16 at 15:54
  • On the matter of speed in accessing array elements, you might want to see my answer here: http://stackoverflow.com/a/36160922/341994 – matt Jul 10 '16 at 16:20
  • @matt very interesting – Bobj-C Jul 10 '16 at 16:21

2 Answers2

7

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Yup, and it crashes while doing a release because when replacing the value with a subscript, ARC will try to deallocate the previous reference type instance that was contained at that location. His code would have worked using a struct (with no ref inside) or other value types. – uraimo Jul 10 '16 at 15:53
2

It seems likely that you are looking for Array's withUnsafeBufferPointer method. This gives you direct access to the array's contiguous in-memory storage. You might want to start with something like this:

    let arr = Array("hello there".characters)
    arr.withUnsafeBufferPointer { p -> Void in
        var i = 0
        repeat {
            print("character:", p[i])
            i += 1
        } while i < p.count
    }
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Note that this will crash for an empty array as the `repeat` will be evaluated before the `while` – you could just use a for loop instead. – Hamish Jul 10 '16 at 16:09
  • @originaluser2 Agreed, I just wanted to give something to get started with, as I said. I don't actually have any notion what, if anything, the OP wants to accomplish. – matt Jul 10 '16 at 16:18