Skip to content

making a copy of struct and taking address of it returns pointer to the same struct #59341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mobiletoly opened this issue Mar 31, 2023 · 8 comments

Comments

@mobiletoly
Copy link

mobiletoly commented Mar 31, 2023

What version of Go are you using (go version)?

$ go version

1.20.2

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env

GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/pochkin/Library/Caches/go-build"
GOENV="/Users/pochkin/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/pochkin/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/pochkin/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.20.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.20.2/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
AR="ar"
CC="cc"
CXX="c++"
CGO_ENABLED="1"
GOMOD="/Users/pochkin/Projects/my/goquick/templates/golang/db-mongodb/go.mod"
GOWORK="/Users/pochkin/Projects/my/goquick/go.work"
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/f2/smcpzg4s1yq_tc4vfmltrcwh0000gn/T/go-build44889709=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I have a structure that I pass a pointer to function. Under some conditions I want to create a copy of the structure and get a pointer to it, because I want to modify a copy, not the structure itself. So doing something like this:

v := &(*c)

where "c" is a pointer to a structure.

Seems like "v" points to the same address as "c" and therefore when I modify fields in "v" - it actually modifies these fields in "c" as well (since pointer points to the same address). But if I split it in two different lines, such as

v := *c
v1 := &v

then now I can modify "v1" without affecting "c".

What did you expect to see?

Obviously if I make a copy of structure and take address of it, I would expect for pointer to point to a new structure, not to old one.

I guess some optimization happens when compiler sees &* but it really shouldn't, because developer might have a very clear intent to create a copy of a struct and get a pointer.

@zigo101
Copy link

zigo101 commented Mar 31, 2023

*c doesn't mean a copy of c. It means the referenced value of c.

1 similar comment
@zigo101
Copy link

zigo101 commented Mar 31, 2023

*c doesn't mean a copy of c. It means the referenced value of c.

@mobiletoly
Copy link
Author

as per example above:

v := &(*c)

and

v := *c
v1 := &v

it would be reasonable to assume that they should have the same outcome. but in case of first example if you modify v - it modifies c as well. and if you modify v1 - it does not modify c.

how would you document a difference so new developers would understand it easily?

@dominikh
Copy link
Member

&*c gets simplified to c, it does not take the address of the result of dereferencing c. This is also the most natural behavior: we take addresses of variables; *c doesn't exist anywhere concrete. (the &Struct{...} literal syntax is a special case, and it's more like an allocation than an address-of operation.)

@mobiletoly
Copy link
Author

mobiletoly commented Mar 31, 2023

I don't think that &*c should be simplified to c, because your intense if very clear - you create a temporary variable by dereferencing *c and then you take an address of it. so for me it does not look like the most natural behavior - because I explicitly insist of (*c) first and then asking for address of this operation. based on my examples above - we are doing pretty much the same - we create a temporary variable. it should be a real clear explanation why &*c gets optimized to just c while if we do:

v := *c
v1 := &v

we will actually get a real copy of c and then a pointer to that newly copied c. otherwise it is so easy to introduce bugs (actually I discovered a bug because of this behavior in my code).

@randall77
Copy link
Contributor

From the spec:

For an operand x of pointer type *T, the pointer indirection *x denotes the variable of type T pointed to by x.

Note that it does not say "... *x denotes a new variable of type T copied from the variable of type T pointed to by x".
So &*x points to the same variable as x does.

Among other reasons, this is needed so expressions like (*x).foo (more succinctly written as x.foo), change what x points to instead of changing an introduced and immediately thrown away temporary.

@seankhliao
Copy link
Member

closing as working as intended.

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Mar 31, 2023
@mobiletoly
Copy link
Author

Thank you for pointing to spec. Appreciate it.

@golang golang locked and limited conversation to collaborators Apr 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants