(*it)->method() vs (**it).method
Asked Answered
F

5

7

When iterating over an vector (or other container) of pointers, is there any difference between and/or over advantage using:

for (it = v.begin(); it != v.end(); ++it) {
    (*it)->method();
}

or

for (it = v.begin(); it != v.end(); ++it) {
    (**it).method();
}
Footboard answered 8/11, 2012 at 19:5 Comment(4)
I don't see any particular advantage of one over the other (both are unreadable anyway).Faxen
Choose the one that's prettier.Wilbertwilborn
Why do you have a vector of pointers? Who owns the pointers (not the vector). If you use boost::ptr_vector it takes ownersip of the pointer but also exposes its members as references to the object (not the pointer) thus no need for this double de-referencing.Disproportionate
Every c++ question bring up boost at some point : ). For good reasons I am sure. On this job I don't have boost available.Footboard
P
11

In the C language, there is no difference. However, in C++, the -> operator can be overloaded, whereas the member selection . operator cannot.

So in (*foo)->bar *foo could designate a class object which acts as a smart pointer, though this won't happen if foo is an iterator over a standard C++ container of pointers, which means that *foo evaluates to a pointer.

And in (**foo).bar, **foo has to be a class object with a member called bar (which is accessible).

The unary * can also be overloaded (which is how the iterator foo, a class object, returns the object which it references).

In other words, the expressions can diverge in meaning, but if *foo is a pointer to a class/struct, then the equivalence inherited from the C language applies: (*ptr).member is equivalent to ptr->member.

Perdita answered 8/11, 2012 at 19:8 Comment(10)
The * operator can be overloaded too, so where does that make the difference (except for the fact that different operators are used and could therefore be overloaded). Of course someone might thing it's a great idea to overload those operators differently, but that should be obvious as beeing a very bad idea.Panada
Anybody that overloads -> without overloading * to make the usage symantically equivelent is going to be in for a lot of trouble (ie they are insane). Also note the OP pointed out the container contains pointers.Disproportionate
What people can and cannot do is neither here nor there. A provably correct C++ program that requires no diagnostics could have semantically incompatible overloads of * and -> in the same class.Perdita
Also still not relevant to the question as it is about pointers. Also the point of the site is to be helpful not try and spout irreverent corner case that don't apply 99.999% of the time.Disproportionate
I agree with Loki. This answer is irrelevant to the question at hand.Luther
Thanks to Loki's tactfully delivered, constructive criticism, I have made a few improvements to the (already accepted) answer.Perdita
Interesting to know that in C there is no difference.Footboard
@LokiAstari, I take it you think that overriding * to be a kleene star is insane? I've seen it done a number of times.Maidstone
@Yakk: That's not quite what I said. If '*' and '->' provide semantically different meanings.Disproportionate
Yes -- they put the kleene star in front of the RE (or language element) to represent 0 or more of that in a grammar matching engine. Unary * has a semantic meaning that isn't dereference. Admittedly, -> probably isn't used!Maidstone
D
3

They are equivalent: as defined the standard (for pointers)

5.2.5 Class member access [expr.ref]
2: For the first option (dot) the first expression shall have complete class type. For the second option (arrow) the first expression shall have pointer to complete class type. The expression E1->E2 is converted to the equivalentform(*(E1)).E2; the remainder of 5.2.5 will address only the first option (dot).65 In either case, the id-expression shall name a member of the class or of one of its base classes.

Classes and overriding the -> and * operator are not relevant here as the container contains pointers.

Thus:

(*it)->method();

// Is equivelent to:

(*((*it))).method();

// This is equivelent too:

(**it).method(); // thus both expressions are identical in this context.
Disproportionate answered 8/11, 2012 at 19:35 Comment(2)
In the first "equivalent to" is (*((*it))).method(); different from (*(*it)).method();? I.e. the parenthesis does something?Footboard
@Ross: No I was just being accurate to the standard. In which E1 is represented by (*it).Disproportionate
Z
2

No. -> just says to access the struct as a pointer. . acts as if it's just a struct. It's synactic - there's no difference in terms of functionality.

Edit: You can overload -> to make it do something different, although assuming you don't do that it's the same. Not sure why you'd do that, but if you did then you'd have to dereference your struct again using an additional *.

Zohara answered 8/11, 2012 at 19:8 Comment(1)
Um, yes, there is a difference. operator-> can be overloaded, and the compiler will chain calls to operator-> to get to an object.Hausner
C
0

They're the same. You can use one or the other depending on the coding conventions you use, for example.

-> and * operators can be overloaded, while . operator cannot.

Circinus answered 8/11, 2012 at 19:8 Comment(0)
L
0

On Ubuntu 12.04 a list iterator implemented in the following way:

template<typename _Tp>
struct _List_iterator
{

  // ...
  reference
  operator*() const
  { return static_cast<_Node*>(_M_node)->_M_data; }

  pointer
  operator->() const
  { return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }

  // ...
Loutitia answered 8/11, 2012 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.