我想知道在slice被追加后指向slice元素的指针的行为是什么,例如:
package main
import "fmt"
func main() {
my_slice := []int {3}
silly_ptr := &my_slice[0]
// Do we know that silly_ptr points to value equal 3
// all the time? (If we don't explicitly change it).
fmt.Printf("%p\n", silly_ptr)
fmt.Println(*silly_ptr)
for i := 0; i < 10; i++ {
my_slice = append(my_slice, i)
}
silly_ptr_2 := &my_slice[0]
fmt.Printf("%p\n", silly_ptr_2)
fmt.Println(*silly_ptr_2)
}Produces:(没有惊喜)
0xc20800a200
3
0xc20805a000
3我知道当追加到动态数组时,在某些点上我们会重新填充整个数组,因此原始数组元素的内存地址是不可靠的。据我所知,类似的代码在c++中是有效的,但是silly_ptr可以指向任何东西。如果vector被借用,rust不允许修改它,因此上面的逻辑将不会编译。
但是Go呢?我知道,通过escape analysis,返回指向局部变量的指针是有效的,该变量将在堆上为您创建。我的直觉告诉我,同样的逻辑也适用于上面的情况。silly_ptr所指向的内存位置将不会被重新填充,因此将始终存储3 (如果我们不明确地更改它)。是这样的吗?
发布于 2015-07-26 12:01:33
不,它不会总是存储3。
Go有内存管理功能。只要存在指向切片的底层数组的活动指针,底层数组就会被固定,它就不会被垃圾回收。如果有指向基础数组元素的指针,则可以更改该元素的值。例如,
package main
import (
"fmt"
)
func pin() *int {
s := []int{3}
fmt.Println(&s[0])
a := &s[0]
s = append(s, 7)
fmt.Println(&s[0])
return a
}
func main() {
a := pin()
fmt.Println(a, *a)
*a = 42
fmt.Println(a, *a)
}输出:
0xc82000a340
0xc82000a360
0xc82000a340 3
0xc82000a340 42切片描述符包含指向底层数组的指针,因此您可以看到与切片类似的内容。例如,
package main
import (
"fmt"
)
func pin() []int {
s := []int{3}
fmt.Println(&s[0])
d := s
s = append(s, 7)
fmt.Println(&s[0])
return d
}
func main() {
d := pin()
fmt.Println(&d[0], d)
d[0] = 42
fmt.Println(&d[0], d)
}输出:
0xc82000a340
0xc82000a360
0xc82000a340 [3]
0xc82000a340 [42]https://stackoverflow.com/questions/31633330
复制相似问题