2

I've been given some C++ code that has a list/iterator of the following struct.

typedef struct{
  int x;
  int y;
}my_struct;

std::list<my_struct> the_list;
std::list<my_struct>::iterator the_iter = the_list.begin();

The code then accesses x and y of the_iter this way:

(*the_iter).x;
(*the_iter).y;

I want to change these to the more readable version:

the_iter->x;
the_iter->y;

From my C perspective, this is totally fine for pointer dereferencing. Is this also the case for iterators? Is there any reason why my colleague would use (*pointer). instead of p->

Resigned June 2023
  • 4,638
  • 3
  • 38
  • 49
Hosack
  • 1,597
  • 1
  • 8
  • 10

4 Answers4

6

Considering the general case, it could happen that some iterator class did not provide operator ->, and doing (*it).x would be the only possible way. Another possibility is that operator * and operator -> have some non-standard semantics and are not interchangeble. However, this class would fail to satisfy any iterator concept, and, technically, would not be an iterator.

In your case it is std::list<T>::iterator, for which it->x and (*it).x are equivalent.

lisyarus
  • 15,025
  • 3
  • 43
  • 68
5

This answer has background on why the two methods both exist for pointers if they achieve the same thing: https://stackoverflow.com/a/6632474/3113508

Your change would be perfectly fine (and probably preferred by most) for STL iterators for the same reason the -> operator is generally preferred for use with pointers.

However, be aware that the unary * operator and the ->operator can be overloaded to provide semantically different behavior in user-defined classes. So, potentially someone could choose to use * or -> in a different way, such that foo->bar is no longer the same as (*foo).bar. Make sure you are familiar with the documentation for the classes that you are using.

Community
  • 1
  • 1
Scott M
  • 482
  • 3
  • 14
2

No, style preferences / knowledge of -> would be the only reason they would use (* a). vs ->.

Austinh100
  • 598
  • 3
  • 13
1

The difference is that operator-> can be overloaded to return multiple levels of proxy objects with overloaded operator-> to which it is then again applied recursively, until a plain pointer is returned, like in Wrapping C++ Member Function Calls by Bjarne Stroustrup.

Whereas operator. cannot be overloaded in C++.

The example from that paper is:

#include<iostream>

using namespace std;

void prefix() { cout<< "prefix"; }
void suffix() { cout<< " suffix\n"; }

template<class T>
class Call_proxy{
  T* p;
public:
  Call_proxy(T* pp) :p(pp){ }
  ˜Call_proxy() { suffix() ; }
  T* operator->() { return p; }
};

template<class T>
class Wrap{
  T* p;
public:
  Wrap(T* pp) :p(pp) { }
  Call_proxy<T> operator->() { prefix() ; return Call_proxy<T>(p) ; }
};

class X{ // one user class
public:
X() { cout<< "make an X\n"; }
  int f() const{ cout<< "f()"; return 1; }
  void g() const{ cout<< "g()"; }
};

class Y{ // another user class
public:
  Y() { cout<< "make a Y\n"; }
  void h() const{ cout<< "h()"; }
};

int main() // simple test code
{
  Wrap<X> xx(new X) ;
  Wrap<Y> yy(new Y) ;
  if(xx->f()) cout<< "done\n";
  xx->g() ;
  yy->h() ;
  return 0;
}

Each call of xx and yy is bracketed by a pair of prefix()/suffix() calls, so the program produced:

make an X
make a Y
prefix f() suffix
done
prefix g() suffix
prefix h() suffix
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271