Мне дали код C ++, который имеет список / итератор следующей структуры.
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_iter
сюда:
(*the_iter).x;
(*the_iter).y;
Я хочу изменить их на более читаемую версию:
the_iter->x;
the_iter->y;
С моей точки зрения C, это совершенно нормально для разыменования указателей. Это также касается итераторов? Есть ли причина, по которой мой коллега использовал бы (*pointer).
вместо p->
Рассматривая общий случай, может случиться так, что некоторый класс итератора не обеспечит operator ->
и делает (*it).x
будет единственным возможным способом. Другая возможность заключается в том, что operator *
а также operator ->
имеют некоторую нестандартную семантику и не являются взаимозаменяемыми. Однако этот класс не сможет удовлетворить какую-либо концепцию итератора и, технически, не будет итератором.
В вашем случае это std::list<T>::iterator
, для которого it->x
а также (*it).x
эквивалентны.
Этот ответ имеет представление о том, почему оба метода существуют для указателей, если они достигают одного и того же: https://stackoverflow.com/a/6632474/3113508
Ваше изменение было бы совершенно нормально (и, вероятно, большинством) для итераторов STL по той же причине ->
Оператор, как правило, предпочтительнее для использования с указателями.
Тем не менее, имейте в виду, что унарный *
оператор и ->
Оператор может быть перегружен для обеспечения семантически различного поведения в пользовательских классах. Таким образом, потенциально кто-то может выбрать для использования *
или же ->
по-другому, так что foo->bar
больше не совпадает с (*foo).bar
, Убедитесь, что вы знакомы с документацией для используемых вами классов.
Нет, стилевые предпочтения / знание ->
будет единственной причиной, по которой они будут использовать (* a).
против ->
,
Разница в том, что operator->
может быть перегружен для возврата нескольких уровней прокси-объектов с перегруженными operator->
к которому он затем снова применяется рекурсивно, пока не будет возвращен простой указатель, как в Обертывание вызовов функций-членов C ++ от Bjarne Stroustrup.
В то время как operator.
не может быть перегружен в C ++.
Пример из этой статьи:
#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;
}
Каждый звонок xx
а также yy
заключен в скобки парой вызовов prefix () / suffix (), поэтому программа создала:
make an X
make a Y
prefix f() suffix
done
prefix g() suffix
prefix h() suffix