英文:
Behavior of a pointer to an element of `slice` after the `slice` had been appended to
问题
我想知道在将slice
追加后,指向slice
元素的指针的行为是什么,例如:
package main
import "fmt"
func main() {
my_slice := []int{3}
silly_ptr := &my_slice[0]
// 我们是否知道silly_ptr始终指向值为3的元素?
// (如果我们没有显式更改它)。
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)
}
输出结果为(没有意外):
0xc20800a200
3
0xc20805a000
3
我知道在向动态数组追加元素时,某些时候我们需要重新填充整个数组,因此原始数组元素的内存地址是不可靠的。据我所知,类似的代码在C++
中是有效的,但silly_ptr
可能指向任何内容。Rust
不允许在借用vector
时对其进行修改,因此上述逻辑将无法编译。
那么Go
呢?我知道通过逃逸分析
,在函数中返回局部变量的指针是有效的,变量将在堆上为您创建。我的直觉告诉我,在上述情况下也适用相同的逻辑。指向silly_ptr
的内存位置不会被重新填充,因此将始终存储3
(如果我们没有显式更改它)。这样对吗?
英文:
I am wondering what is the behavior of a pointer to an element of slice
after the slice
had been appended to, for example:
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: (no surprises)
0xc20800a200
3
0xc20805a000
3
I know that when appending to dynamic array, at certain points we have repopulate the entire array, and therefore memory address of the original array elements is not reliable. To the best of my knowledge similar code is valid in c++
, but silly_ptr
could be pointing to anything. rust
does not allow mutating a vector
if it is being borrowed, so the above logic would not compile.
But what about Go
? I know that by escape analysis
it is valid to return a pointer to a local variable, the variable would be just created on the heap for you. My intuition tells me that the same logic applies in the above case. The memory location where silly_ptr
is pointing to will not be repopulated, and hence will always store 3
(if we don't explictly change it). Is this right?
答案1
得分: 1
不,它不会始终存储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]
英文:
No, it will not always store 3.
Go has memory management. As long as there is an active pointer to an underlying array for a slice, the underlying array is pinned, it will not be garbage collected. If you have a pointer to an element of an underlying array, you can change the value of the element. For example,
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)
}
Output:
0xc82000a340
0xc82000a360
0xc82000a340 3
0xc82000a340 42
A slice descriptor contains a pointer to an underlying array so you can see something similar with a slice. For example,
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)
}
Output:
0xc82000a340
0xc82000a360
0xc82000a340 [3]
0xc82000a340 [42]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论