Ответ 1
Если вы хотите получить полный контроль над областью памяти, которую вы сами выделяете, вы можете использовать UnsafePointer
и co:
// allocate enough memory for ten Ints
var ump = UnsafeMutablePointer<Int>.alloc(10)
// memory is in an uninitialized raw state
// initialize that memory with Int objects
// (here, from a collection)
ump.initializeFrom(reverse(0..<10))
// memory property gives you access to the underlying value
ump.memory // 9
// UnsafeMutablePointer acts like an IndexType
ump.successor().memory // 8
// and it has a subscript, but it not a CollectionType
ump[3] // = 6
// wrap it in an UnsafeMutableBufferPointer to treat it
// like a collection (or UnsafeBufferPointer if you don't
// need to be able to alter the values)
let col = UnsafeMutableBufferPointer(start: ump, count: 10)
col[3] = 99
println(",".join(map(col,toString)))
// prints 9,8,7,99,5,4,3,2,1,0
ump.destroy(10)
// now the allocated memory is back in a raw state
// you could re-allocate it...
ump.initializeFrom(0..<10)
ump.destroy(10)
// when you're done, deallocate the memory
ump.dealloc(10)
Вы также можете указать UnsafePointer
на другую память, такую как память, которую вы передали некоторым C API.
UnsafePointer
может быть передан в C-функции, которые принимают указатель на непрерывный блок памяти. Поэтому для ваших целей вы можете передать этот указатель в функцию типа mlock
:
let count = 10
let ump = UnsafeMutablePointer.allocate<Int>(count)
mlock(ump, UInt(sizeof(Int) * count))
// initialize, use, and destroy the memory
munlock(ump, UInt(sizeof(Int) * count))
ump.dealloc(count)
Вы даже можете хранить свои собственные пользовательские типы:
struct MyStruct {
let a: Int
let b: Int
}
var pointerToStruct = UnsafeMutablePointer<MyStruct>.alloc(1)
pointerToStruct.initialize(MyStruct(a: 1, b: 2))
pointerToStruct.memory.b // 2
pointerToStruct.destroy()
pointerToStruct.dealloc(1)
Однако помните, что если вы делаете это с помощью классов или даже массивов или строк (или структуры, которая их содержит), то все, что вы будете держать в своей памяти, указывает на другую память, что эти объекты распределять и владеть. Если это имеет значение для вас (т.е. Вы делаете что-то особенное для этой памяти, например, обеспечиваете ее, в вашем примере), это, вероятно, не то, что вы хотите.
Таким образом, либо вам нужно использовать объекты фиксированного размера, либо использовать дальнейшее использование UnsafePointer
для хранения указателей на большее количество областей памяти. Если им не нужно динамически изменять размер, то только одно выделение небезопасного указателя, возможно, завернутое в UnsafeBufferPointer
для интерфейса коллекции, могло бы это сделать.
Если вам нужно больше динамического поведения, ниже приведена очень простая реализация коллекции, которая может по мере необходимости изменять размер, которая может быть улучшена, чтобы охватить специальную логику обработки памяти:
// Note this is a class not a struct, so it does NOT have value semantics,
// changing a copy changes all copies.
public class UnsafeCollection<T> {
private var _len: Int = 0
private var _buflen: Int = 0
private var _buf: UnsafeMutablePointer<T> = nil
public func removeAll(keepCapacity: Bool = false) {
_buf.destroy(_len)
_len = 0
if !keepCapacity {
_buf.dealloc(_buflen)
_buflen = 0
_buf = nil
}
}
public required init() { }
deinit { self.removeAll(keepCapacity: false) }
public var count: Int { return _len }
public var isEmpty: Bool { return _len == 0 }
}
Чтобы покрыть требования MutableCollectionType
(т.е. CollectionType
плюс присваиваемый индекс):
extension UnsafeCollection: MutableCollectionType {
typealias Index = Int
public var startIndex: Int { return 0 }
public var endIndex: Int { return _len }
public subscript(idx: Int) -> T {
get {
precondition(idx < _len)
return _buf[idx]
}
set(newElement) {
precondition(idx < _len)
let ptr = _buf.advancedBy(idx)
ptr.destroy()
ptr.initialize(newElement)
}
}
typealias Generator = IndexingGenerator<UnsafeCollection>
public func generate() -> Generator {
return Generator(self)
}
}
И ExtensibleCollectionType
, чтобы обеспечить динамический рост:
extension UnsafeCollection: ExtensibleCollectionType {
public func reserveCapacity(n: Index.Distance) {
if n > _buflen {
let newBuf = UnsafeMutablePointer<T>.alloc(n)
newBuf.moveInitializeBackwardFrom(_buf, count: _len)
_buf.dealloc(_buflen)
_buf = newBuf
_buflen = n
}
}
public func append(x: T) {
if _len == _buflen {
reserveCapacity(Int(Double(_len) * 1.6) + 1)
}
_buf.advancedBy(_len++).initialize(x)
}
public func extend<S: SequenceType where S.Generator.Element == T>
(newElements: S) {
var g = newElements.generate()
while let x: T = g.next() {
self.append(x)
}
}
}