Ответ 1
Я думаю, что это соответствующее предложение:
ISO/IEC 14882: 2003 С++ Standard 23.1.1/12 - Последовательности
В таблице 68 перечислены операции последовательности которые предоставляются для некоторых типов последовательные контейнеры, но не другие. Реализация должна обеспечивать операции для всех типов контейнеров показано в столбце "контейнер" и должны осуществлять их, чтобы амортизированное постоянное время.
+----------------------------------------------------------------------------+ | Table 68 | +--------------+-----------------+---------------------+---------------------+ | expression | return type | operational | container | | | | semantics | | +--------------+-----------------+---------------------+---------------------+ | a.front() | reference; | *a.begin() | vector, list, deque | | | const_reference | | | | | for constant a | | | +--------------+-----------------+---------------------+---------------------+ | a.back() | reference; | *--a.end() | vector, list, deque | | | const_reference | | | | | for constant a | | | .............................................................................. . . . . . . . . . . .............................................................................. | a.pop_back() | void | a.erase(--a.end()) | vector, list, deque | .............................................................................. . . . . . . . . . .
Итак, для перечисленных контейнеров не только должен возвращаться итератор из end()
, декрементный итератор также должен быть разуплотненным. (Если контейнер не пуст, конечно, это вызывает поведение undefined.)
Фактически реализации vector
, list
и deque
, которые поставляются вместе с компилятором Visual С++, точно соответствуют таблице. Конечно, это не означает, что каждый компилятор делает это так:
// From VC++ <list> implementation
reference back()
{ // return last element of mutable sequence
return (*(--end()));
}
const_reference back() const
{ // return last element of nonmutable sequence
return (*(--end()));
}
Обратите внимание на код в таблице:
ISO/IEC 14882: 2003 Стандарт С++ 17.3.1.2/6 - Требования
В некоторых случаях семантический требования представлены как C + + код. Такой код предназначен как спецификация эквивалентности построить другую конструкцию, а не обязательно как способ построения должны быть реализованы.
Итак, хотя верно, что реализация не может реализовать эти выражения в терминах begin()
и end()
, стандарт С++ указывает, что эти два выражения эквивалентны. Другими словами, a.back()
и *--a.end()
являются эквивалентными конструкциями в соответствии с вышеприведенным предложением. Мне кажется, что это означает, что вы должны иметь возможность заменить каждый экземпляр a.back()
на *--a.end()
и наоборот и иметь код, который все еще работает.
Согласно Бо Перссону, пересмотр стандарта С++, который у меня под рукой имеет дефект относительно таблицы 68.
Предлагаемое разрешение:
Измените спецификацию в таблице 68 "Необязательные операции последовательности" в 23.1.1/12 для "a.back()" из
*--a.end()
к
{ iterator tmp = a.end(); --tmp; return *tmp; }
и спецификация для "a.pop_back()" из
a.erase(--a.end())
к
{ iterator tmp = a.end(); --tmp; a.erase(tmp); }
Похоже, вы все равно можете уменьшить итератор, возвращенный из end()
, и разыщите декрементированный итератор, если он не временный.