In my library, I am creating a series of objects efficiently from data. I then want to put them, in the order that they're created, into an array. I could just use Array.append, but I've measured and this isn't fast enough for my purposes. Also, it needs to be an Array and not some other type, e.g. ContiguousArray. So, I'm using Apple Developer Documentation to set up the array efficiently. However, when I do the first subscript assignment, i.e. buffer[0] = MyType(...), I get an EXC_BAD_ACCESS crash. If I first call memset(buffer.baseAddress, 0, count * MemoryLayout<Element>.stride) though, it won't crash. Here's my code with that memset call:
let array: [Element] = try Array(unsafeUninitializedCapacity: count) { (buffer, countToAssign) in
memset(buffer.baseAddress, 0, count * MemoryLayout<Element>.stride)
var isAtEnd = false
for i in 0..<count {
do {
buffer[i] = try decoder.unbox(currentValue, as: Element.self)
JNTDocumentNextArrayElement(currentValue, &isAtEnd)
} catch {
countToAssign = i
throw error
}
}
}
This seems to work, and is substantially faster. As for why it crashes without the memset call, @Lantua has pointed out in the documentation for UnsafeMutablePointer that it says "Do not assign an instance of a nontrivial type through the subscript to uninitialized memory. Instead, use an initializing method, such as initialize(to:count:) .". Is the same true of UnsafeMutable*Buffer*Pointer? If so, is memset enough to be safe? And why does this crash occur in the first place?
FYI, here's another example of it initialized from a Sequence. However, this is also too slow for my purposes:
let array: [Element] = try Array(unsafeUninitializedCapacity: count) { (buffer, countToAssign) in
let sequence: ElementSequence<Element> = ElementSequence(decoder: decoder, count: count, value: currentValue)
let _ = buffer.initialize(from: sequence)
countToAssign = sequence.i
if let error = sequence.error {
throw error
}