#c #containers #libstdc
#c #контейнеры #libstdc
Вопрос:
Я могу создавать начальные и конечные итераторы, используя std::begin()
и std::end()
.
например:
int arr[4][4] = <something here>;
auto begin_it = std::begin(arr);
auto end_it = std::end(arr);
Однако, почему у нас нет std::front()
и std::back()
. Есть ли какая-либо конкретная причина, по которой они должны быть опущены?
Есть ли какие-либо похожие функции, которые я мог бы использовать (кроме begin и end, конечно)?
Комментарии:
1. Как часто вам нужно использовать их в массивах? Вы все время используете
begin
/end
/size
(или альтернативы, которые они заменяют).2. Не уверен, есть ли причина их опускать, вероятно, просто нет причин включать эти функции. Если они вам нужны по какой-то причине, вы могли бы просто написать свои собственные
3. Мое мнение таково, что
front
это часто приводило бы к UB в пустом или не определенном переднем контейнере, ноbegin
не приводило бы к этому, пока он не разыменован.4. @LouisGo, но они могли бы подтвердить это, не так ли?
Ответ №1:
Не все контейнеры имеют постоянный доступ к последнему элементу списка.
std::forward_list
например.
Ответ №2:
Как и сказал Маршалл Клоу, следует учитывать несогласованное время доступа между контейнерами.
Мое мнение, front часто вызывал бы UB в пустом или не определенном контейнере front, но begin не вызывал бы этого, пока он не разыменован.
std::vector v;
auto item = std::front(v); // This line immediately cause undefined behavior.
Если std::front
существует, это может вызвать больше проблем, чем удобства, которые оно приносит.
Потому что каждый вызов front
должен выполняться после empty
. Тогда это два вызова функции, чтобы сделать это удобным..
std::vector v;
// ...
if( !v.empty() ){
auto item = std::front(v);
// ...tasks
}
ХМ .. Удобно ли это?
В то время как программист мог бы front
сознательно пройти мимо *begin(container)
и использовать его перед проверкой. Все, что мы сохранили, — это просто звездочка.
std::vector v;
// ...
if( !v.empty() ){
auto item = *std::begin(v);
// ...tasks
}
Комментарии:
1. Я думаю, у нас уже есть вторая:
std::empty
Ответ №3:
Есть ли какая-либо конкретная причина, по которой они должны быть опущены?
Есть ли какая-либо конкретная причина для их включения?
Вещи не помещаются в стандартную библиотеку только потому, что они могут быть. Предполагается, что стандартная библиотека будет состоять из полезных функций, шаблонов и тому подобного. «Бремя доказательства» лежит на человеке, который хочет, чтобы что-то было включено. Только после того, как вариант использования был установлен, представлен комитету по стандартам и отклонен указанным комитетом, было бы точно назвать что-то «опущенным».
При этом существует несколько потенциальных причин, по которым что-то не может быть включено в стандартную библиотеку, и «бесполезно» — только одна из них. Другие возможные причины включают «недостаточно хорошую реализацию на всех платформах» и «о, мы об этом не подумали». Хотя я не знаю, какая причина здесь применима, я могу дать некоторую пищу для размышлений, сравнив std::end()
с гипотетической std::back()
.
Можно использовать std::end()
с массивом в стиле C (известного размера) или любым другим объектом, удовлетворяющим требованиям «Контейнера», таким как все контейнеры в стандартной библиотеке. Она обладает большой полезностью при циклическом перемещении по контейнерам, что является достаточно распространенной операцией. Результатом добавления std::end()
в стандартную библиотеку является то, что многие алгоритмы стандартной библиотеки больше не нуждаются в шаблонной специализации для обработки массивов в стиле C. (По общему признанию, циклы for на основе диапазона имели аналогичный эффект.)
Можно было бы использовать std::back()
с массивом в стиле C (известного размера), a std::array
или чем-либо еще, отвечающим требованиям «SequenceContainer», таким как строки, векторы, запросы, списки и списки пересылки (и ничего больше из стандартной библиотеки). У нее есть утилита в … гм… Я рисую пробел, но я предоставляю возможность общего использования для back()
, хотя, вероятно, это и близко не так распространено, как зацикливание.
Поскольку std::back()
это было бы применимо в меньшем количестве ситуаций, чем std::end()
, это могло быть упущено из виду. В то же время, поскольку std::back()
она была бы применима в меньшем количестве ситуаций, чем std::end()
, она может не соответствовать критериям «полезности» для включения в стандартную библиотеку.
Есть ли какие-либо похожие функции, которые я мог бы использовать (кроме begin и end, конечно)?
Вы могли бы переключиться с массивов в стиле C на std::array
, а затем использовать std::array::back()
. В конце концов, std::array
это просто массив в стиле C, завернутый так, чтобы выглядеть как контейнер непрерывной последовательности. Объявление типа длиннее, но функции, которые вы ищете, становятся легко доступными.
Целью стандартной библиотеки является поддержка массивов в стиле C, потому что это библиотека, предназначенная для использования в коде, о котором авторы библиотеки и не мечтали. Если вы не пишете библиотеку, вам, вероятно, на самом деле не нужно поддерживать массивы в стиле C.