views:

232

answers:

4

We all know about -> vs . speed diff to access members in c/c++, but I am hard to find any clues of the actual cost of the simple dot operator.

I imagine its something like address-of-struct + offset, also assume the offset being the sum of all sizeof-s of all preceding members. Is this (roughly) correct?

Then compared to -> who much faster it is? Twice?
(having seen some asm, here on SO, about . access being one instruction, I guess there is some magic about it)

Also, how much slower is, compared to local variable?

Thank You

EDIT:
I failed to ask it correctly, I guess.

To try to clear things up:
By "-> vs ." I meant "using pointer to access the struct" vs "direct member access" - (link).
And then I was just curious: "Ok, and what about the dot access itself?It sourly cost something." So I asked the question.

"Dot operator cost c/c++" itself might be absurd/nonsense/naive question, still it does get the answers I was looking for. Can't say it better now.

Thanks

+5  A: 

Any decent compiler will calculate the address of struct field at compile time so the cost of . should be zero.

In other words access to struct field using . is as costly as access to variable.

qrdl
What about calcualtion/loading of struct address and summation?
Basilevs
@Basilevs What about asking meaningful questions?
qrdl
That was not really a question. I was trying to say that your estimate for cost of dot operator is essentially incorrect :)
Basilevs
@Basilevs In order to claim someone incorrect you have to back it by something, otherwise YOUR comment is essentially incorrect.
qrdl
Dummy00001 has already explained that at least this pointer should be read and the member address calculated to use dot operator. Even if this pointer is cached this still requires at least one CPU tick. More probably two.
Basilevs
@Basilevs Read OP's question once again, especially after the edit. By `.` OP meant direct member access, without any pointers, so your comments are inapplicable.
qrdl
@Basilevs: Or zero. Many instruction set architectures (including x86) contain offset addressing modes for memory access instructions. This means if you have *address* in a register, you can have an "read from ( *address* + x )" instruction. The offset is essentially free in this case.
slacker
A: 

It depends on a huge number of things.

The . operator can vary from being cheaper than accessing a local variable or using -> to being much more expensive than either.

This isn't a sensible question to ask.

Joe Gauterin
Under what circumstance can accessing a member from an object through `.` be *more* expensive than doing the same through a pointer and `->`? It can be equivalent when using reference/pointers in some cases, but I cannot think on any case where it can be more costly.
David Rodríguez - dribeas
If the `->` accesses an object on the stack and the `.` accesses an object on the heap and triggers a page fault, the `->` will be much cheaper than the `.`. That's why I said it's not a sensible question to ask - the answer depends on *where* an object is stored not on the syntax used to access it.
Joe Gauterin
+5  A: 

We all know about -> vs . speed diff to access members in c/c++, but I am hard to find any clues of the actual cost of the simple dot operator.

The "we all" apparently doesn't include me. I'm not aware of any significant difference (especially in C++) between -> vs. ..

I imagine its something like address-of-struct + offset, also assume the offset being the sum of all sizeof-s of all preceding members. Is this (roughly) correct?

Yes.

Then compared to -> how much faster it is? Twice? (having seen some asm, here on SO, about . access being one instruction, I guess there is some magic about it)

Both -> and . involve calculation of an effective address and that is the most expensive operation (beside the actual memory access). If pointer (on the left of ->) is used very often (e.g. this) then it is highly likely to be already cached by compiler in a CPU register, effectively negating any possible difference between -> and ..

Well, this is a pointer, everything belonging the object inside a method is effectively prefixed with this->, yet C++ programs haven't slowed to a crawl.

Obviously, if . is applied to a reference, then it is 100% equivalent of ->.

Also, how much slower is it, compared to local variable?

Hard to evaluate. Essentially difference in meta assembler would be: two asm ops to access the local variable (add the offset of the variable on the stack to the stack pointer; access the value) vs. three asm ops to access attribute of an object via pointer (load the pointer to the object; add the offset; access the value). But due to compiler optimizations the difference is rarely noticeable.

Often it is difference between local and global variables which is standing out: address of local variable/object's attribute has to be computed, while all global variables have unique global address calculated at link time.

But overhead of the field/attribute access is really negligible and minuscule compared to e.g. overhead of a system call.

Dummy00001
"Obviously, if `.` is applied to a reference, then it is 100% equivalent of `->`." Eh, not so obvious. Consider `int i; int j = 5;` I think you'd be hard-pressed to find a compiler that generates the same code as `int i; int * const j = *j = 5;`. References are not necessarily "easy" pointers. Still +1 though, pointing out `this->` is good.
GMan
Juts because the variable is on the stack does not mean you can miss out the `load the pointer to the object` step.
Martin York
@Martin: "variable on stack" == "attribute of the object on stack", since there is no pointer to the object. Offset of the attribute can be calculated (relative to the start of the stack frame) already at the compile time.
Dummy00001
@Dummy00001: Absolutely not true. You need to know the address of the variable not the attribute. Any method you call is going to need to know the this pointer so there is no way to avoid this step. Therefore accessing a local variable will cost exactly the same as one through the pointer (as you have to get the pointer to the local variable). Try it.
Martin York
@Martin: "Therefore accessing a local variable will cost exactly the same as one through the pointer (as you have to get the pointer to the local variable)." You forget that pointer has to be saved somewhere too. `int a; a;` - you get to the `a` via stack frame + offset of `a` inside the stack frame. `int *a; *a;` - you first have to get the `a` (as the local variable) only then access the `*a`.
Dummy00001
@Dummey00001: I think you just prove my point. But anyway rather then argue about what you think should happen. Just get a compiler and try (like I have).
Martin York
@Martin: I see disasm output of C++ object code at least once per month. And at least on four platforms. I think I simply explain myself not well enough and your point does come through.
Dummy00001
A: 

I would say the difference of cost isn't in the operators themselves, but in the cost of accessing the left-side object.

ptr->variable

should produce a similar asm output than

(*ptr).variable // yeah I am using a '.' because it's faster...

therefore your question is kind of nonsensical as it is.

I think I understand what you meant though, so I'll try to answer that instead.

The operators themselves are nearly costless. They only involve computing an address. This address is expressed as the address of the object plus an offset (likely fixed at compile time and therefore a constant in the program for each field). The real cost comes from actually fetching the bytes at this address.

Now, I don't understand why it would be more costly to use a -> vs a . since they effectively do the same thing, there can be a difference of access though in this case:

struct A { int x; };

void function(A& external)
{
  A local;

  external.x = local.x;
}

In this case, accessing external.x is likely to be more costly because it necessitates accessing memory outside of the scope of the function and therefore the compiler cannot know in advance whether or not the memory will have already been fetched and put in the processor cache (or a register) etc...

On the other hand local.x being local and stored on the stack (or a register), the compiler may optimize away the fetch part of the code and access local.x directly.

But as you notice there is no difference between using -> vs ., the difference is in using a local variable (stored on the stack) vs using a pointer / reference to an externally supplied object, on which the compiler cannot make an assumption.

Finally, it's important to note that if the function was inlined, then the compiler could optimize its use at the caller's site and effectively use a slightly different implementation there, but don't try to inline everything anyway: first of all the compiler will probably ignore your hints, and if you really force it you may actually lose performance.

Matthieu M.