`std::back()` аналогичная функция в C

#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.