В книге «Экскурсия по C++» (третье издание для C++20
) Бьярна Страуструпа, раздел 18.5.2 упакованной задачи, у нас есть этот фрагмент кода:
// compute the sum of [beg:end) starting with the initial value init
double accum(vector<double>::iterator beg, vector<double>::iterator end, double init)
{
return accumulate(&*beg, &*end, init);
}
Почему Страуструп использовал здесь &*
итератора вместо самого итератора? Есть ли какое-либо преимущество или разница в этом?
это ошибка? Нет, это очень намеренно. Это точка обучения. И это не работает для других типов контейнеров, которые не хранят свои элементы последовательно.
вы получите ссылку на double, но накопление принимает итератор в качестве параметра
вы получите ссылку на двойной Не совсем верно. Вы возразите double*
, который сам по себе (в данном случае) является допустимым итератором.
Так почему же предпочесть double* std::vector<double>::iterator ?
Я очень надеюсь, что позже он скажет, что &*end
— это неопределенное поведение (при условии, что end
получено из метода end()
).
Это хороший вопрос. Я тоже не вижу здесь преимущества. Я бы перечитал раздел, где это делается, чтобы посмотреть, объяснит ли он свои рассуждения несколькими страницами раньше или позже.
@Yksisarvinen совсем нет!
Примечание: здесь не используется stl
. stl
относится к стандартной библиотеке шаблонов, чрезвычайно влиятельной библиотеке 1990-х годов, которая послужила источником огромного вдохновения и во многих случаях стала ранними реализациями стандартной библиотеки C++. Даже 25 лет спустя часто можно увидеть отголоски в названии деталей реализации.
@kingsjester Даже итераторы в непрерывной памяти иногда оборачиваются какими-то причудливыми вещами (то есть не всегда необработанными указателями) для целей отладки и т. д. Разыменовывая итератор и беря адрес объекта, вы получаете необработанный указатель - и, предположительно, быстрее итерация. Хотя я не понимаю, зачем это в книге...
Так почему же предпочесть double*
std::vector<double>::iterator
? Я думаю, это было просто для примера параллелизма, когда вектор накопления разделяется на отдельные части. Сейчас читаю 18.5.2, разочарован тем, что оплошность &*end
не была выявлена. Это ошибка, исправленная в опечатке.
@Элджей, спасибо, опубликуй это как ответ, и я приму его
@Eljay, «мы не должны передавать пары указателей, если вместо этого мы можем использовать диапазон» на самом деле не говорит о том, что это вообще была ошибка.
@TedLyngmo • Верно, не указано явно. Избежал ошибки, избавившись от оскорбительного кода, сделав его немного по-другому и продемонстрировав span
. Я позволю кому-то другому дать лучший ответ. (Я уже достаточно побеспокоил Бьярна в этом году.)
Дубликат решает потенциальную проблему с кодом, но не объясняет, почему Страуструп решил использовать здесь именно этот трюк.
@user4581301 user4581301 Технически это правда. Учитывая опечатки, это, скорее всего, ошибка, поэтому я не уверен, что очень полезно иметь для этого отдельный вопрос (особенно тот, на который, вероятно, сможет ответить только Страуструп, если они еще не задокументировали его где-нибудь). В качестве альтернативы, дубликат цели можно отредактировать, добавив вопрос «почему Страуструп сделал это», а затем ответить на адрес, который можно добавить туда. Если ни одно из вышеперечисленных решений не является хорошим решением, у меня нет сильных чувств по поводу использования этой цели для обмана.
@cigien Ни я, ни я бы удалили его, а не просто прокомментировали, но Элджей отмечает в комментарии выше, что этот фрагмент кода исправлен в опечатках. Это в значительной степени приводит к ответу: «Ой».
Было время, когда не существовало концепции непрерывных итераторов, когда необработанные указатели могли использоваться функцией, которой требовался непрерывный диапазон.
Как указал Элджей в комментарии, тот факт, что Б. Страуструп использует здесь double*
вместо std::vector<double>::iterator
, в данном случае кажется ошибкой, поскольку он исправил это в опечатке.
Этот синтаксис представляет собой неопределенное поведение, как описано в этом ответе.
Подумайте о том, что
std::vector<double>::iterator::operator*
на самом деле делает/возвращает. Вероятно, здесь есть обман.