交换指针:相当于 `std::unique_ptr::swap`
Swapping pointers: equivalent of `std::unique_ptr::swap`
我不确定如何将 C++ std::unique_ptr::swap
翻译成 Go。
我在 C++ 中使用 std::unique_ptr<T,Deleter>::swap:
std::unique_ptr<bool[]> maskA{new bool[num]};
std::unique_ptr<bool[]> maskB{new bool[num]};
// ...
maskA.swap(maskB); // Swap operation
如果我只在 Go 中使用一个简单的 maskA, maskB = maskB, maskA
,我会遗漏什么吗?
maskA := make([]bool, num)
maskB := make([]bool, num)
// ...
maskA, maskB = maskB, maskA
这个交换是否具有相同的功能?
简答:
这在功能方面是等效的,但实际性能影响不同。使用 *[]bool
作为最接近的等价物。
属性:
assignment with exchange 具有以下属性:
maskA
和 maskB
的值将交换
- 因为这些是切片,底层布尔数组未复制
- 由于编译器优化,切片描述符可能也不会被复制
最后两点很重要,并且由于切片的构建方式:它们是指向底层数组的小描述符。有关详细信息,请参阅 slice internals。
C++ 和 Go 的区别:
在 C++ 中,一个 unique_ptr<foo>
总是持有一个 *foo
并且交换只涉及交换地址,这具有可预测的性能影响。
在 Go 中,类型是你给它的任何类型,编译器将复制值。工作量取决于类型:
- 如果这些很大(例如:数组:
[1000]bool
),它可能会变得昂贵
- 如果它们是您现在拥有的切片(例如:
[]bool
),将复制切片描述符。
- 如果它们是指针(例如:
*[]bool
),这将与 C++ 相同
因此,为了保证与 C++ 代码的等效性,您应该使用指向 bool slice (*[]bool
) 的指针作为您的 Go 类型。
Go 优化:
Go 编译器将尝试优化变量交换。
这是一个简单的例子:
func main() {
a := make([]bool, 0)
b := make([]bool, 0)
fmt.Println(a, b)
a, b = b, a
fmt.Println(a, b)
}
我们可以使用GOSSAFUNC=main go build .
转储编译期间的优化步骤
查看生成的 ssa.html
文件,我们可以看到 a, b = b, a
行被完全删除,以下代码更改为类似 fmt.Println(b, a)
.
的内容
当发生这种情况时,您的交换变得只是编码的精确性并且没有性能影响,但是情况并非总是如此(编译器优化非常专业,在某些情况下它不能这样做。例如:交换两个结构字段成员不能被优化掉)。
不等比较:
比较两者有点奇怪。 C++ 中更接近的等效项是要交换的两个普通变量(无论是否为指针)。 unique_ptr
的主要目标是简化对象所有权并在 unique_ptr
超出范围时删除基础对象。
Go 没有 unique_ptr
的等价物,主要是因为它不需要,所有内存都是垃圾回收的。
我不确定如何将 C++ std::unique_ptr::swap
翻译成 Go。
我在 C++ 中使用 std::unique_ptr<T,Deleter>::swap:
std::unique_ptr<bool[]> maskA{new bool[num]};
std::unique_ptr<bool[]> maskB{new bool[num]};
// ...
maskA.swap(maskB); // Swap operation
如果我只在 Go 中使用一个简单的 maskA, maskB = maskB, maskA
,我会遗漏什么吗?
maskA := make([]bool, num)
maskB := make([]bool, num)
// ...
maskA, maskB = maskB, maskA
这个交换是否具有相同的功能?
简答:
这在功能方面是等效的,但实际性能影响不同。使用 *[]bool
作为最接近的等价物。
属性:
assignment with exchange 具有以下属性:
maskA
和maskB
的值将交换- 因为这些是切片,底层布尔数组未复制
- 由于编译器优化,切片描述符可能也不会被复制
最后两点很重要,并且由于切片的构建方式:它们是指向底层数组的小描述符。有关详细信息,请参阅 slice internals。
C++ 和 Go 的区别:
在 C++ 中,一个 unique_ptr<foo>
总是持有一个 *foo
并且交换只涉及交换地址,这具有可预测的性能影响。
在 Go 中,类型是你给它的任何类型,编译器将复制值。工作量取决于类型:
- 如果这些很大(例如:数组:
[1000]bool
),它可能会变得昂贵 - 如果它们是您现在拥有的切片(例如:
[]bool
),将复制切片描述符。 - 如果它们是指针(例如:
*[]bool
),这将与 C++ 相同
因此,为了保证与 C++ 代码的等效性,您应该使用指向 bool slice (*[]bool
) 的指针作为您的 Go 类型。
Go 优化:
Go 编译器将尝试优化变量交换。
这是一个简单的例子:
func main() {
a := make([]bool, 0)
b := make([]bool, 0)
fmt.Println(a, b)
a, b = b, a
fmt.Println(a, b)
}
我们可以使用GOSSAFUNC=main go build .
查看生成的 ssa.html
文件,我们可以看到 a, b = b, a
行被完全删除,以下代码更改为类似 fmt.Println(b, a)
.
当发生这种情况时,您的交换变得只是编码的精确性并且没有性能影响,但是情况并非总是如此(编译器优化非常专业,在某些情况下它不能这样做。例如:交换两个结构字段成员不能被优化掉)。
不等比较:
比较两者有点奇怪。 C++ 中更接近的等效项是要交换的两个普通变量(无论是否为指针)。 unique_ptr
的主要目标是简化对象所有权并在 unique_ptr
超出范围时删除基础对象。
Go 没有 unique_ptr
的等价物,主要是因为它不需要,所有内存都是垃圾回收的。