13

Is there any difference in performance - or otherwise - between:

ptr->a();

and

(*ptr).a(); 

?

Rachel
  • 2,181
  • 2
  • 18
  • 20

3 Answers3

15

[Edit]

If the variable is defined as T* (where T is some type) then both -> and * are the same (unless ptr is null).

If the variable is an instance of a class (by value or by reference) then -> and * should behave the same (per best practice) but this requires the class to overload them the same way.

Itay Maman
  • 30,277
  • 10
  • 88
  • 118
  • 1
    -> and * don't operate on the type themselves T, but on a type of T*, which is a pointer. – Brian R. Bondy Mar 18 '10 at 13:56
  • 8
    If the underlying class *does* overload `->` or `*` it should overload both so that it is still the same. Otherwise it is badly designed. – Tadeusz Kopec for Ukraine Mar 18 '10 at 13:59
  • @Brian `->` and `*` operate on anything that defines `operator->` and `operator*`. *And* also on all pointer types. – Tadeusz Kopec for Ukraine Mar 18 '10 at 14:01
  • I know that the results are the same; can anyone confirm that performance - speed, efficiency - is the same? – Rachel Mar 18 '10 at 14:34
  • 2
    @Tadeusz Kopec: Read the answer by Jeremy Bell: `operator->` has special behavior that makes `x->y` inconsistent with `(*x).y` in some cases, and the behavior cannot be simulated with `operator*` – David Rodríguez - dribeas Mar 18 '10 at 14:52
  • 2
    Rachel: I know people have heard this over and over again but: Why? Who cares? Use the readable one, performance is a *second concern*. Your first concern is writing your application in an easy to manage way. Only when you find performance lacking should you even care about performance. That said, you have to *profile*: time the code and see which is faster. However in this case, they are the same thing. There should be no difference. You are new-ish to programming in C++, I'm guessing, so worry about C++, not speed. – GManNickG Mar 18 '10 at 14:53
  • 3
    @Tadeusz: You can overload -> But it will apply to the class not the pointers of the class. For example Cat c; c->f(), it will not apply to Cat *p = &c; p->f(); I'm not sure why this is so highly voted up because it is wrong. – Brian R. Bondy Mar 18 '10 at 14:59
  • @Brian: I agree with you, but the original question does specify whether that variable is defined as T* or T. So, the answer is general and captures all cases – Itay Maman Mar 18 '10 at 15:35
  • @Brian: so it should be clarified - if applied to pointers `(*).` and `->` are perfectly the same, no matter what pointee type is. If applied to object of some class, it calls appropriate operator overloads if defined or does not compile if no such overload exists. Implementations of `operator*` and `operator->` may vary, but general guideline is 'do like primitives do' so making `*` and `->` do different things I consider bad design. – Tadeusz Kopec for Ukraine Mar 18 '10 at 15:35
  • @Itay, @Tadeusz: Agree, the user didn't specify explicitly but I think he meant a pointer type. I agree with both of your final statements though. – Brian R. Bondy Mar 18 '10 at 15:40
  • @GMan - Simple: I do not believe in doing things without understanding why you're doing them. – Rachel Mar 18 '10 at 17:32
  • @Rachel: You didn't ask why, you asked which is more efficient. If your "Why" is "it's the most efficient", fine, but I warn against that. Micro-optimizations lose to good programming. – GManNickG Mar 18 '10 at 19:01
  • @GMan: Change that to "what you're doing." If there are two ways to do something, there's usually a difference. Otherwise we'd only need one way to do it. In this case I was guessing that perhaps the difference would be optimization. This was an attempt to understand the entire picture, rather than an "it works so just use it." – Rachel Mar 18 '10 at 19:21
  • @Rachel: Your question above was misleading, then. Asking which is more efficient has nothing to do with understanding why they are the same. – GManNickG Mar 18 '10 at 19:31
  • "(unless ptr is null)" -> do you mean "(unless ptr is null, because then both are undefined behavior)" (which is actually the case) or do you mean "(unless ptr is null, because then one behaves different)"? If the latter, then which one do you think behaves different? – Johannes Schaub - litb Mar 18 '10 at 19:35
12

Since you are asking for it in the comments. What you are probably looking for can be found in the Standard (5.2.5 Class member access):

3 If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;

The compiler will produce the exact same instructions and it will be just as efficient. Your machine will not know if you wrote "->" or "*.".

Lucas
  • 13,679
  • 13
  • 62
  • 94
8

The -> operator is special in that in most cases it "drills-down" recursively until the result of the expression is no longer something that has an overloaded -> operator defined for it. The (*subxpression).x expression only does one dereference on subexpression, so if the result of (*subexpression) is another pointer, then this wouldn't compile (you would need to write (*(*subexpression)).x. See the following code for a better illustration:

#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass() : x(0) {}
    int x;
};

class MyPtr
{
private:
    MyClass* mObj;
public:
    MyPtr(MyClass* obj) : mObj(obj) {}
    MyClass* operator->() 
    {
        return mObj;
    }
};

int main() 
{
    MyClass obj;
    MyClass* objCPtr = &obj;
    MyClass** objCHandle = &objCPtr;
    MyPtr ptr(&obj);
    cout << ptr->x << endl;
    cout << (*(*objCHandle)).x << endl;
}

Note however, that this would not compile:

cout << objCHandle->x << endl;

Because the drill down behavior of -> only occurs when the left hand side of the expression is a class, struct, union, or generic type. In this case, objCHandle is a MyClass**, so it doesn't qualify.

Andrew Aylett
  • 39,182
  • 5
  • 68
  • 95
Jeremy Bell
  • 5,253
  • 5
  • 41
  • 63