11

Having

struct Person {
   string name;
};

Person* p = ...

Assume that no operators are overloaded.


Which is more efficient (if any) ?

(*p).name vs. p->name

Somewhere in the back of my head I hear some bells ringing, that the * dereference operator may create a temporary copy of an object; is this true?


The background of this question are cases like this:

Person& Person::someFunction(){
    ...
    return *this;
}

and I began to wonder, if changing the result to Person* and the last line to simply return this would make any difference (in performance)?

Kalamar Obliwy
  • 861
  • 2
  • 8
  • 13
  • At this point you should much more worry about readability, and since `->` is the more common syntactic sugar, `(*i).m` is frowned upon in many places. Only if any profiling shows that there might be a problem related to this you should start worrying about its efficiency. – PlasmaHH May 03 '13 at 09:22
  • 3
    I'd expect the compiler to produce exactly the same result. You can answer this yourself, compile both codes to assembler and check the produced code. – bluehallu May 03 '13 at 09:22
  • I asked this question because of the *background* I described - many basic operators usually return a reference to self, and I see very often them returning `*this`; – Kalamar Obliwy May 03 '13 at 09:23
  • 1
    `*p` is an l-value (you can do `*p = something;`). How could this create a temporary object? – Angew is no longer proud of SO May 03 '13 at 09:25
  • @Angew Good point, I was thinking about `Person& p2 = *p;` and the possibility they dont refer to the same object – Kalamar Obliwy May 03 '13 at 09:26
  • 3
    @KalamarObliwy There is no such possibility. The built-in pointer dereference operator `*` returns an l-value designating the object pointed to (you can think of it as a reference to it). – Angew is no longer proud of SO May 03 '13 at 09:29
  • Some containers like [Boost's `fibonacci_heap`](http://www.boost.org/doc/libs/1_55_0/doc/html/boost/heap/fibonacci_heap.html) have a `handle_type` that doesn't even support `operator->` (probably only out of forgetfulness), so if you're being extremely general, you should probably use explicit dereferencing. I don't recommend it though. – user541686 Jun 20 '14 at 09:34

4 Answers4

9

There's no difference. Even the standard says the two are equivalent, and if there's any compiler out there that doesn't generate the same binary for both versions, it's a bad one.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
8

When you return a reference, that's exactly the same as passing back a pointer, pointer semantics excluded.
You pass back a sizeof(void*) element, not a sizeof(yourClass).

So when you do that:

Person& Person::someFunction(){
    ...
    return *this;
}

You return a reference, and that reference has the same intrinsic size than a pointer, so there's no runtime difference.

Same goes for your use of (*i).name, but in that case you create an l-value, which has then the same semantics as a reference (see also here)

Community
  • 1
  • 1
Gui13
  • 12,993
  • 17
  • 57
  • 104
  • This is a good point about the size of return. Can you explain, what does `*p` do just by itself then? The result of it is a Person& or Person, or const Person&? – Kalamar Obliwy May 03 '13 at 09:29
  • You get an `l-value`, which references the object's address, if I read http://stackoverflow.com/questions/11347111/dereferencing-a-pointer-when-passing-by-reference correctly and according to wikipedia: http://en.wikipedia.org/wiki/Value_(computer_science) – Gui13 May 03 '13 at 09:33
2

Yes, it's much harder to read and type, so you are much better off using the x->y than (*x).y - but other than typing efficiency, there is absolutely no difference. The compiler still needs to read the value of x and then add the offset to y, whether you use one form or the other [assuming there are no funny objects/classes involved that override the operator-> and operator* respectively, of course]

There is definitely no extra object created when (*x) is referenced. The value of the pointer is loaded into a register in the processor [1]. That's it.

Returning a reference is typically more efficient, as it returns a pointer (in disguise) to the object, rather than making a copy of the object. For objects that are bigger than the size of a pointer, this is typically a win.

[1] Yes, we can have a C++ compiler for a processor that doesn't have registers. I know of at least one processor from Rank-Xerox that I saw in about 1984, which doesn't have registers, it was a dedicated LiSP processor, and it just has a stack for LiSP objects... But they are far from common in todays world. If someone working on a processor that doesn't have registers, please don't downvote my answer simply because I don't cover that option. I'm trying to keep the answer simple.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

Any good compiler will produce the same results. You can answer this yourself, compile both codes to assembler and check the produced code.

bluehallu
  • 10,205
  • 9
  • 44
  • 61