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();
}
Coding Mash
  • 3,338
  • 5
  • 24
  • 45
Ross
  • 14,266
  • 12
  • 60
  • 91
  • I don't see any particular advantage of one over the other (both are unreadable anyway). –  Nov 08 '12 at 19:07
  • Choose the one that's prettier. – Mysticial Nov 08 '12 at 19:08
  • 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. – Martin York Nov 08 '12 at 19:23
  • 1
    Every c++ question bring up boost at some point : ). For good reasons I am sure. On this job I don't have boost available. – Ross Nov 08 '12 at 19:42

5 Answers5

10

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.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • 1
    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. – Grizzly Nov 08 '12 at 19:10
  • 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. – Martin York Nov 08 '12 at 19:29
  • 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. – Kaz Nov 08 '12 at 19:31
  • 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. – Martin York Nov 08 '12 at 19:36
  • I agree with Loki. This answer is irrelevant to the question at hand. – David Hammen Nov 08 '12 at 19:56
  • 1
    Thanks to Loki's tactfully delivered, constructive criticism, I have made a few improvements to the (already accepted) answer. – Kaz Nov 08 '12 at 20:03
  • Interesting to know that in C there is no difference. – Ross Nov 08 '12 at 21:35
  • @LokiAstari, I take it you think that overriding `*` to be a kleene star is insane? I've seen it done a number of times. – Yakk - Adam Nevraumont Nov 08 '12 at 21:57
  • @Yakk: That's not quite what I said. If '*' and '->' provide semantically different meanings. – Martin York Nov 09 '12 at 01:57
  • 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! – Yakk - Adam Nevraumont Nov 09 '12 at 02:14
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.
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • In the first "equivalent to" is `(*((*it))).method();` different from `(*(*it)).method();`? I.e. the parenthesis does something? – Ross Nov 08 '12 at 21:47
  • @Ross: No I was just being accurate to the standard. In which `E1` is represented by `(*it)`. – Martin York Nov 09 '12 at 01:55
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 *.

GraphicsMuncher
  • 4,583
  • 4
  • 35
  • 50
  • Um, yes, there is a difference. `operator->` can be overloaded, and the compiler will chain calls to `operator->` to get to an object. – Pete Becker Nov 08 '12 at 19:14
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.

Synxis
  • 9,236
  • 2
  • 42
  • 64
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); }

  // ...