Bue*_*uer 3 copy-on-write swift
import Foundation
func address(o:UnsafeRawPointer) -> Int {
return Int(bitPattern: o)
}
var originArray = [1,2,3]
var firstArray = originArray
//q.append(4)
print(NSString.init(format: "originArray:%p", address(o: &originArray)))
print(NSString.init(format: "firstArray:%p", address(o: &firstArray)))
Run Code Online (Sandbox Code Playgroud)
调试日志:originArray:0x100b087b0 firstArray:0x100b088c0
上面是我的测试代码。我认为我没有修改 originArray ,比如添加或减少元素。他们应该指向相同的地址。但为什么要尊重
您的代码正在打印数组缓冲区的地址(是将值传递给指针参数时的Array 特殊情况)。然而,在 Swift 3 中,编译器假设运算符的存在意味着&缓冲区被作为可变内存传递,因此(不必要地)在传递其指针值之前使其唯一(通过复制),尽管该指针值被传递为一个UnsafeRawPointer。这就是为什么您会看到不同的地址。
如果删除&运算符并直接传递数组:
func address(_ p: UnsafeRawPointer) {
print(p)
}
var originArray = [1, 2, 3]
var firstArray = originArray
address(originArray) // 0x00000000016e71c0
address(firstArray) // 0x00000000016e71c0
Run Code Online (Sandbox Code Playgroud)
您现在将获得相同的地址,因为编译器现在假设address(_:)不会修改传递的缓冲区的内存,因为它们被传递给UnsafeRawPointer参数。
在 Swift 4 中,这种不一致问题得到了修复,编译器在将指针值传递给参数之前不再使缓冲区唯一UnsafeRawPointer,即使在使用&运算符时也是如此,因此您的代码会表现出预期的行为。
不过,值得注意的是,上述方法并不能保证产生稳定的指针值。
来自 Swift 博客文章“与 C 指针交互”:
即使您将相同的变量、数组或字符串作为多个指针参数传递,您每次也可能收到不同的指针。
我相信在两种情况下数组无法满足这种保证(可能还有更多):
如果数组正在查看非连续存储中的元素
SwiftArray可以查看非连续存储中的元素,例如当它包装NSArray. 在这种情况下,当将其传递给指针参数时,必须创建一个新的连续缓冲区,从而为您提供不同的指针值。
如果缓冲区在作为可变内存传递时被非唯一引用
如前所述,当将数组传递给可变指针参数时,首先将其缓冲区设置为唯一,以保留值语义,因为假设函数将执行缓冲区的突变。
因此,如果复制缓冲区,您将获得与将数组传递给不可变指针参数时不同的指针值。
尽管这两点都不适用于您给出的示例,但值得注意的是,编译器在传递给指针参数时仍然不能保证指向数组缓冲区的稳定指针值。
为了保证结果可靠,您应该withUnsafeBytes(_:)在以下对象上使用该方法ContiguousArray:
var originArray: ContiguousArray = [1, 2, 3]
var firstArray = originArray
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000102829550
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000102829550
Run Code Online (Sandbox Code Playgroud)
这是因为withUnsafeBytes(_:)记录为接受:
UnsafeRawBufferPointer带有指向数组连续存储的参数的闭包。如果不存在这样的存储,则创建它。
并ContiguousArray保证:
[it] 始终将其元素存储在连续的内存区域中
就像 一样Array,ContiguousArray使用写时复制以获得值语义,因此您仍然可以使用它来检查发生突变时何时复制数组的缓冲区:
var originArray: ContiguousArray = [1, 2, 3]
var firstArray = originArray
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray[0] = 4
originArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000103103eb0
firstArray.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000100e764d0
Run Code Online (Sandbox Code Playgroud)