`slice`被追加后,指向`slice`元素的指针的行为。

huangapple go评论93阅读模式
英文:

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 &quot;fmt&quot;

func main() {
	my_slice := []int {3}

	silly_ptr := &amp;my_slice[0]
	// Do we know that silly_ptr points to value equal 3
	// all the time? (If we don&#39;t explicitly change it).

	fmt.Printf(&quot;%p\n&quot;, silly_ptr)
	fmt.Println(*silly_ptr)

	for i := 0; i &lt; 10; i++ {
		my_slice = append(my_slice, i)
	}

	silly_ptr_2 := &amp;my_slice[0]

	fmt.Printf(&quot;%p\n&quot;, 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 (
	&quot;fmt&quot;
)

func pin() *int {
	s := []int{3}
	fmt.Println(&amp;s[0])
	a := &amp;s[0]
	s = append(s, 7)
	fmt.Println(&amp;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 (
	&quot;fmt&quot;
)

func pin() []int {
	s := []int{3}
	fmt.Println(&amp;s[0])
	d := s
	s = append(s, 7)
	fmt.Println(&amp;s[0])
	return d
}

func main() {
	d := pin()
	fmt.Println(&amp;d[0], d)
	d[0] = 42
	fmt.Println(&amp;d[0], d)
}

Output:

0xc82000a340
0xc82000a360
0xc82000a340 [3]
0xc82000a340 [42]

huangapple
  • 本文由 发表于 2015年7月26日 11:24:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/31633330.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定