gomemory-managementreturnheap-memoryrvo

Will Go make a copy of my struct if I return by value, instead of a pointer?


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?


Solution

  • You can check it by following these steps:

    1. Write your program in a file say main.go like this: https://play.golang.org/p/iwxai0EHa40

    2. Execute the command go build -gcflags=-m main.go

    3. 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.