У меня очень большая структура, и я хочу убедиться, что ее не копируют без нужды. Как сделать для него контейнер для копирования при записи?
Как создать контейнер с семантикой копирования при записи? (Быстрый)
Ответы (3)
Копирование при записи обычно представляет собой struct
оболочку над некоторым поддерживающим объектом.
public final class MutableHeapStore<T>: NonObjectiveCBase
{
public typealias Storage = T
public private(set) var storage: Storage
public init(storage: Storage)
{
self.storage = storage
}
}
public struct COW<T>
{
public typealias Storage = MutableHeapStore<T>
public typealias Value = T
public var storage: Storage
public init(storage: Storage)
{
self.storage = storage
}
public var value: Value
{
get
{
return storage.storage
}
set
{
if isUniquelyReferenced(&storage)
{
storage.storage = newValue
}
else
{
storage = Storage(storage: newValue)
}
}
}
public init(_ value: Value)
{
self.init(storage: Storage(storage: value))
}
}
extension COW: CustomStringConvertible
{
public var description: String
{
return String(value)
}
}
Уловка заключается в утверждении isUniquelyReferenced
каждый раз, когда значение в штучной упаковке изменяется. Если на базовый объект хранения имеется отдельная ссылка, ничего не нужно делать. Однако, если существует другая ссылка, необходимо создать новое хранилище.
Является ли этот код потокобезопасным? Он так же безопасен, как и любой другой тип значения, например Int
или Bool
.
isUniquelyReferenced
никогда не было шансов быть выполненным, я добавляю оператор печати внутри, никогда не получал вывода
- person dispute; 26.02.2016
Вот более простой пример.
struct COWExample1<T> {
private var box = Box<[T]>(value: [T]())
var count: Int {
return box.value.count
}
mutating func append(e: T) {
ensureBoxUniqueRefed()
box.value.append(e)
}
private mutating func ensureBoxUniqueRefed() {
if isUniquelyReferencedNonObjC(&box) == false {
box = box.duplicated()
}
}
}
private final class Box<T> {
var value: T
init(value: T) {
self.value = value
}
func duplicated() -> Box<T> {
return Box(value: value)
}
}
Предыдущие ответы не ошибочны, но есть гораздо более простой способ. У команды Swift есть список советов по эффективности, и они говорят:
Самый простой способ реализовать копирование при записи - это составить существующие структуры данных с копированием при записи, такие как массив.
Нет ничего проще!
isKnownUniquelyReferenced
вместоisUniquelyReferenced
- person Dan Lee   schedule 22.06.2017