У меня есть (без комментариев) исходный файл, который я пытаюсь понять.
static const Map *gCurMap;
static std::vector<Map> mapVec;
затем
auto e = mapVec.end();
auto i = mapVec.begin();
while(i!=e) {
// ...
const Map *map = gCurMap = &(*(i++));
// ...
}
Я не понимаю что &(*(i++))
делает. Не компилируется при использовании i++
, но для меня это выглядит так же, потому что я «увеличиваю» i
, то я запрашиваю значение по данному адресу, а затем я запрашиваю адрес этого значения ?!
Не за что. &*x
такой же как operator&(operator*(x))
, который может быть чем угодно.
Это верно только для типы указателей лайк T * p
тот &*p
такой же как p
, Но C ++ имеет пользовательские типы и перегружаемые операторы.
Оператор разыменования (*
) обычно перегружается для итераторов, чтобы они возвращали ссылку на элемент контейнера. Эффект оператора амперсанда (&
) на элементе контейнера лежит автор класса; если вы хотите взять адрес безоговорочно, вы должны использовать std::addressof(*i++)
(из вашего любимого заголовка<memory>
).
mapVec.begin()
возвращает итератор с перегруженным operator++
, «Разыменование» (перегружено operator*
) итератора, чтобы добраться до map
объект. Ссылка &
хорошо, потому что map
является указателем, поэтому он присваивается адресу объекта из разыменования i
, Мы не можем просто i++
потому что это все равно будет итератор, а не фактический map
объект.
i
итератор, *i
является объектом, на который указывает этот итератор, и &*i
это адрес этого объекта. Если бы итератор был просто старым указателем, это было бы ненужным, но обычно это не так просто. Итератор часто имеет некоторый тип класса, который перегружает operator*
чтобы позволить вам получить доступ к объекту, на который он указывает. Так что это в основном преобразование из итератора в элемент в указатель на этот элемент.
Я бы переместил приращение на следующую строку, потому что это только затрудняет понимание данной строки. Это было бы эквивалентно, потому что значение i++
просто i
и приращение происходит потом.
Это не то же самое: i
это итератор. Разыменование итератора дает ссылку на некоторый объект, т.е. T&
для какого-то типа T
, Взятие адреса такого объекта дает T*
адрес объекта в месте нахождения i
, То, что итератор также увеличивается в том же выражении, является просто деталью и, вероятно, является плохой идеей (постинкремент обычно менее эффективен, чем предварительный инкремент, и нет реальной необходимости постинкрементно увеличивать итератор в отрывке кода: он также может быть предварительно увеличенным в каком-то другом месте).