【问题标题】:Behavior of a pointer to an element of `slice` after the `slice` had been appended to将“切片”附加到“切片”元素后的指针的行为
【发布时间】:2015-10-16 11:19:51
【问题描述】:

我想知道在将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)
}

产生:(没有惊喜)

0xc20800a200
3
0xc20805a000
3

我知道当附加到动态数组时,在某些时候我们已经重新填充了整个数组,因此原始数组元素的内存地址是不可靠的。据我所知,类似的代码在c++ 中有效,但silly_ptr 可能指向任何东西。 rust 不允许在 vector 被借用时对其进行变异,因此上述逻辑将无法编译。

但是Go 呢?我知道 escape analysis 返回指向局部变量的指针是有效的,该变量将在堆上为您创建。我的直觉告诉我,同样的逻辑也适用于上述情况。 silly_ptr 指向的内存位置不会被重新填充,因此将始终存储3(如果我们不明确更改它)。是这样吗?

【问题讨论】:

    标签: pointers go slice


    【解决方案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]
    

    【讨论】:

    • 我应该更清楚一点,我不想考虑我们明确更改指针指向的值的情况。但是你说:“只要有一个指向切片的底层数组的活动指针,底层数组是固定的,它就不会被垃圾回收。”这似乎回答了我的问题:silly_ptr 将始终指向等于 3 的值,除非我们明确更改该值,对吗?您知道有关该主题的任何好的资源吗?
    • @Akavall:我的回答表明您可以安全地使用指针来读取和写入元素值。 Go 垃圾收集项目的文本是:垃圾收集手册:自动内存管理的艺术(Chapman & Hall/CRC 应用算法和数据结构系列)R. Jones、A. Hosking、E. Moss。
    猜你喜欢
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 2015-05-01
    • 1970-01-01
    • 2018-08-31
    • 2016-10-16
    • 2015-11-09
    相关资源
    最近更新 更多