如何临时安全正确地将[[T]]转换为UnsafePointer <unsafepointer <t >>

时间:2018-08-18 21:46:26

标签: swift

我需要调用采用2d数组的C函数。未来的数组是在Swift中创建的,通常为[String],但我对[[T]]的情况也很感兴趣。

我正在调用的API指定了它的函数总是在必要时复制传递给它们的数据,所以我不想自己创建内容的副本只是为了传递它,而我只需要担心指针在我可以将它们传递给C函数之前一直有效。我目前的做法是

    let addressArray = someArray.map { (array) in
        array.withUnsafeBufferPointer({ (buffer) in
            // get an array of addresses to each individual member
            return buffer.baseAddress
        })
    }

addressArray.withUnsafeBufferPointer { bufferPointer in
     someCFunction(bufferPointer.baseAddress)
     // do something with someArray to attempt to ensure that the pointers are valid past the lifetime of the withUnsafeBufferPointer call
}

这是可行的,但是由于据说从withUnsafeBufferPointer返回的指针仅在该范围内有效,所以这显然是错误的(尽管可以肯定,始终要求someArray保持活动直到我用someCFunction完成后,我非常有信心它不会在短期内中断)。但是必须有更好的方法。它是什么?

2 个答案:

答案 0 :(得分:0)

根据您的经验,您的代码似乎偶尔会起作用。但是正如您所写的那样,您的代码是错误的,因为withUnsafeBufferPointer返回的指针仅在其闭包参数范围内有效。

我不明白您的意思短期内不会破坏,但我建议您不要对未记录和不清楚的行为充满信心。

您可能需要创建一些稳定的指针,可以通过显式分配区域来实现。

当我需要UnsafePointer<UnsafePointer<T>>来传递嵌套数组[[T]]的内容时,我会写这样的东西。 (假设T原始类型。)

let bufPtrArray = someArray.map {subArray -> UnsafeMutableBufferPointer<T> in
    let bufPtr = UnsafeMutableBufferPointer<T>.allocate(capacity: subArray.count)
    _ = bufPtr.initialize(from: subArray)
    return bufPtr
}
defer {bufPtrArray.forEach{bufPtr in bufPtr.deallocate()}}

let addressArray = bufPtrArray.map {bufPtr in UnsafePointer(bufPtr.baseAddress!)}

addressArray.withUnsafeBufferPointer { bufferPointer in
    someCFunction(bufferPointer.baseAddress!)
    //...
}

或者,如果您不需要在//...中指定的代码,则只需编写:

someCFunction(addressArray)

答案 1 :(得分:-1)

对我来说问题是问题的所有前提似乎都是错误的。 Swift不会复制任何不必要的内容,因此传递实际值不一定没有任何效率。您可以可以传递一个需要C数组的Swift数组。而且,实际上并没有多维C数组之类的东西,因此您可以传递一个一维数组(当然,可以适当安排)。

例如,这是一种方法,该方法采用int数组以及有关“行”(r)和“列”(c)的大小的信息是(来自https://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/的代码):

- (void) giveMeACArray: (int*) array r: (int) r c: (int) c {
    int i, j, count;
    int *arr[r];
    for (i=0; i<r; i++)
        arr[i] = (int *)malloc(c * sizeof(int));
    count = 0;
    for (i = 0; i <  r; i++)
        for (j = 0; j < c; j++)
            arr[i][j] = ++count;
    // let's test it
    for (i = 0; i <  r; i++)
        for (j = 0; j < c; j++)
            printf("%d ", arr[i][j]);
}

让我们说这是一个名为Thing的Objective-C类的实现的一部分。好的,现在我们在Swift中:

let t = Thing()
var arr : [CInt] = [1,2,3,4,5,6,7,8,9,10,11,12]
t.giveMeACArray(&arr, r: 3, c: 4)

没有复制任何内容,并且打印了正确的答案。所以我看不到您的缓冲区指针是什么。