Take this example:
type Foo struct {
num int
}
// func NewFoo() *Foo { // returning a pointer
// return &Foo{33}
// }
func NewFoo() Foo { // NOT returning a pointer
return Foo{33}
}
func main() {
fff := NewFoo()
fmt.Printf("%d\n", fff.num)
}
If NewFoo
returns a pointer, I understand the object is kept in the heap, and fff
receives the pointer to the very same heap-allocated object.
Now, with the second implementation of NewFoo
, which won't return a pointer, will Go return a copy of the stack-allocated struct, or is there something like C++'s RVO taking place?
You can check it by following these steps:
Write your program in a file say main.go
like this: https://play.golang.org/p/iwxai0EHa40
Execute the command go build -gcflags=-m main.go
See the output to really know if it is being copied/inlined. In my case the output I get is:
# command-line-arguments
./main.go:13:6: can inline NewFoo
./main.go:17:6: can inline main
./main.go:18:15: inlining call to NewFoo
./main.go:19:12: inlining call to fmt.Printf
./main.go:19:24: fff.num escapes to heap
./main.go:19:12: io.Writer(os.Stdout) escapes to heap
./main.go:19:12: main []interface {} literal does not escape
<autogenerated>:1: os.(*File).close .this does not escape
This procedure you can follow in any Go program to check if there is any unnecessary heap allocation occurring in your program which you can avoid.
Here is a short article which goes through various ways you can make your program more efficient.