使用解除作用域变量的内存地址是否安全?

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

Is it safe to use the memory address of descoped variables?

问题

这段代码安全吗?当 if 块结束时,b 被解除作用域,但 a 仍然指向 b 的内存地址。在这个简单的例子中,它似乎是有效的(打印了正确的值),但这在语言规范中总是有效吗?

使用 -m 编译以检查编译器优化时,它表示 b 没有逃逸到堆上。

Playground: http://play.golang.org/p/ZzYkMg6FqB

package main

import "fmt"

func main() {
    a := new(int)
    *a = 10
    if *a > 0 {
        b := 5
        a = &b
    }
    fmt.Println(*a)
}
英文:

Is this code safe? b gets descoped when the if block ends, but a still points to b's memory address. In this simple example it seems to work (it prints the right value), but it is in the language specification that this will always work?

Compiling with -m to check the compiler optimizations, it says that b doesn't escape to the heap.

Playground: http://play.golang.org/p/ZzYkMg6FqB

package main

import "fmt"

func main() {
	a := new(int)
	*a = 10
	if *a > 0 {
		b := 5
		a = &b
	}
	fmt.Println(*a)
}

答案1

得分: 2

在Go语言中不存在悬空指针。

即使b超出了作用域,也没有关系;a现在持有该地址,并且会被垃圾回收器扫描到。

英文:

There are no dangling pointers in Go.

It doesn't matter if b is out of scope; a now holds that address and would be scanned by the GC.

答案2

得分: 2

代码是安全的。在Go语言中,任何赋值都具有复制语义,所以

a = &b

等同于

c = &b
a = c

通过给引用赋值,实际上是对该引用进行了一次复制

所以这段代码也是有效的

b := 5
c := &b
a = c
c = nil

fmt.Println(*a)

http://play.golang.org/p/fGTYhEXl1S

英文:

Code is safe. Any assignment in Go has copy semantic, so

a = &b

is equivalent to

c = &b
a = c

assigning to reference you effectively take a copy of this reference

so this sure will also work

b := 5
c := &b
a = c
c = nil

fmt.Println(*a)

http://play.golang.org/p/fGTYhEXl1S

答案3

得分: 1

是的,这完全没问题。

在Go语言中,作用域并不像C或Rust那样重要。Go是一种垃圾回收语言。只要内存可以被访问到,它就不会被释放。在你的例子中,变量a的原始值在下一次垃圾回收时会被释放,因为它不再可访问。

**编辑:**关于栈。在你的程序中,变量b没有逃逸,因为它不需要逃逸。如果你重写你的程序,使得b在栈上分配后会被删除(例如,像这样:链接),你会发现b确实逃逸了。Go的逃逸分析足够聪明,可以看到这样的情况。

英文:

Yes, it's perfectly fine.

Scope doesn't matter in Go as much as in C or Rust. Go is a garbage-collected language. As long as the memory can be reached, it won't be freed. In your example, the original value of a will be freed during the next GC, as it's not reachable any more.

Edit: On stack. In your program, b does not escape because it doesn't need to. If you rewrite your program so that b will be deleted if allocated on stack (for example, like this) you'll see that b does escape. Go's escape analysis is clever enough to see such things.

huangapple
  • 本文由 发表于 2015年1月23日 00:09:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/28093437.html
匿名

发表评论

匿名网友

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

确定