-3

In my code I create a map pointer which I then dereference to retrieve an item.

a := "...big JSON string..."
b := map[string]B{}
json.Unmarshal(a, &b)
c.my_map = &b
...

// and my fetch function does:
result = (*c.my_map)[id]

When dereferencing that map pointer, does it create a temporary copy of the map in memory?

i.e. when I do:

d := *c.my_map

I know I get a copy of the map in d (not a deep copy, but the map itself is duplicated), so I'm thinking that the statement above could end up copying everything...


Why the pointer?

The map is loaded by a go routine and then I save the final pointer in my struct. That save happens with a lock. The loading can be very long (Gb of data) so that's why... (now reading the answer by Zuko) it doesn't look like it would be required at all since a map is passed around as a reference anyway.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 2
    "dereferencing" is no different than normal reading or assignment of the map value. It does not create a deep copy of the map. – JimB Dec 03 '20 at 17:04
  • 1
    If is is declared like `var i *int`: Does `*i` create a copy? If not why should this happen for maps? – Volker Dec 03 '20 at 17:11
  • @JimB So it would make a whole copy just to lookup one item in the map? If it's just a read, then there would be no copy, if it's like the assignment, then there is a full copy of the map itself which, when all the items are not pointers would be very expensive, right? – Alexis Wilke Dec 03 '20 at 17:26
  • 1
    @AlexisWilke, I don't understand what you're asking. Yes, if it's only read then there _may not_ be any copy (this is technically an implementation detail which you can't control), and assignment is _always_ a copy. The map value is a single word however, so it really makes no difference in practice. (this also leads to the question of why you want a pointer to a map in the first place?) – JimB Dec 03 '20 at 17:27
  • @JimB My question is: will the `(*c.my_map)` make a temporary copy before reading and returning the content at `[id]`? In C++, it would return a reference to the map (i.e. the `std::map & m`) which is just a pointer, and I would hope that Go does the same thing, but as you said, it's an implementation detail... Terrible if you ask me. – Alexis Wilke Dec 03 '20 at 17:40
  • I'm still lost here, `*c.my_map` is a map, which if you look at the implementation is a single pointer. "Reading" a value implies copying to _somewhere_ within the hardware, but this is all meaningless at the language level -- reading `(*c.my_map)` is semantically the same as reading the map directly. If you want to verify the instructions used, you need to look at the compiled machine code. – JimB Dec 03 '20 at 17:50
  • 3
    No, there is no copy. No Need to worry. Go isn‘t C++. – Volker Dec 03 '20 at 18:30
  • 1
    To put it another way, even if you assume the most pessimistic possible interpretation, the worst case is still only copying a single word, which is essentially free. – JimB Dec 03 '20 at 18:44
  • 2
    you have not answered the most important question: why you want a pointer to a map in the first place? –  Dec 03 '20 at 19:14

1 Answers1

1

Maps in go much like slices are reference types. It essentially means that when you assign a reference to a new variable or pass a map to a function, the reference to the map is copied.

Take an example below.

 users := map[string]int{
    "1": 1, "2": 2,
 }

 userRef := &users // creates new reference to map reference
 userRef3 := *userRef // returns map reference stored in userRef3 


 // making changes to userRef3 will affect the underlying type
 userRef3["1"] = 101 // now all 3 variables have the same new value

 fmt.Println(users["1"]) //prints 101

So basically you don't need to use a pointer with reference types like maps, slices and raw pointers. But if you did, Go will simply copy the address of the reference type and changes done to it will directly affect the underlying map.

Zuko
  • 2,764
  • 30
  • 30
  • 2
    while i understand you might want to approximate for simplification, a word or two from a referene author is needed. https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go and https://dave.cheney.net/2017/04/30/if-a-map-isnt-a-reference-variable-what-is-it `In the very early days what we call maps now were written as pointers, so you wrote *map[int]int. We moved away from that when we realized that no one ever wrote \`map\` without writing \`*map\`.` –  Dec 03 '20 at 19:13
  • Thanks @mh-cbon for pointing that out. Much appreciated. – Zuko Dec 03 '20 at 19:15
  • Perfect! I tested your sample and indeed it prints 101. So indeed it is just a pointer passed around. Interesting. – Alexis Wilke Dec 03 '20 at 22:34