При итерации по вектору (или другому контейнеру) указателей, есть ли разница между и / или преимуществом, используя:
for (it = v.begin(); it != v.end(); ++it) {
(*it)->method();
}
или же
for (it = v.begin(); it != v.end(); ++it) {
(**it).method();
}
В языке Си нет никакой разницы. Однако в C ++ ->
оператор может быть перегружен, тогда как выбор члена .
оператор не может
Так в (*foo)->bar
*foo
может определить объект класса, который действует как умный указатель, хотя это не произойдет, если foo
является итератором стандартного контейнера указателей C ++, что означает, что *foo
оценивает указатель.
И в (**foo).bar
, **foo
должен быть объектом класса с членом под названием bar
(который доступен).
Одинарный *
также может быть перегружен (как итератор foo
, объект класса, возвращает объект, на который он ссылается).
Другими словами, выражения Можно расходятся в значении, но если *foo
является указателем на класс / структуру, тогда применяется эквивалентность, унаследованная от языка C: (*ptr).member
эквивалентно ptr->member
,
Они эквивалентны: как определено стандартом (для указателей)
5.2.5 Доступ к членам класса [expr.ref] 2: Для первого параметра (точка) первое выражение должно иметь полный тип класса. Для второй опции (стрелка) первое выражение должно иметь указатель на полный тип класса. Выражение E1-> E2 преобразуется в эквивалентную форму (* (E1)). E2; оставшаяся часть 5.2.5 будет касаться только первой опции (точка) .65 В любом случае выражение id должно называть члена класса или одного из его базовых классов.
Классы и переопределение операторов -> и * здесь не имеют значения, так как контейнер содержит указатели.
Таким образом:
(*it)->method();
// Is equivelent to:
(*((*it))).method();
// This is equivelent too:
(**it).method(); // thus both expressions are identical in this context.
Нет. ->
просто говорит, чтобы получить доступ к структуре в качестве указателя. .
действует так, как будто это просто структура. Это синактика — нет никакой разницы с точки зрения функциональности.
Изменить: вы можете перегрузить ->
чтобы заставить его делать что-то другое, хотя, если вы этого не делаете, это то же самое. Не уверен, почему вы это сделаете, но если бы вы это сделали, вам пришлось бы снова разыменовать свою структуру, используя дополнительный *
,
Они одинаковые. Например, вы можете использовать одно или другое в зависимости от используемых вами кодировочных соглашений.
->
а также *
операторы могут быть перегружены, в то время как .
оператор не может
В Ubuntu 12.04 итератор списка реализован следующим образом:
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); }
// ...