ISO / IEC 14882: 2003 C ++ Стандарт 23.1.1 / 12 - Последовательности
Таблицы 68 списковОперации последовательности, которые предоставляются для некоторых типов последовательных контейнеров, но не для других.Реализация должна предоставлять эти операции для всех типов контейнеров, показанных в столбце «контейнер», и должна реализовывать их так, чтобы принимать амортизированное постоянное время.если итератор, возвращаемый из end()
, может быть декремментируемым, декрементированный итератор также должен быть разыменованным.(Если, конечно, контейнер не пустой, это вызывает неопределенное поведение.)
Фактически, реализации vector
, list
и deque
, поставляемые с компилятором Visual C ++, делают это точно так же, как таблица,Конечно, это не означает, что каждый компилятор делает это так:
// From VC++'s <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 / IEC14882: 2003 C ++ Standard 17.3.1.2/6 - Требования
В некоторых случаях семантические требования представлены в виде кода C ++. Такой код предназначен для спецификации эквивалентности конструкции другой конструкции , а не обязательно как способ, которым конструкция должна быть реализована.
Таким образом, правда, что реализация можетне реализуя эти выражения в терминах begin()
и end()
, стандарт C ++ указывает, что оба выражения эквивалентны.Другими словами, a.back()
и *--a.end()
являются эквивалентными конструкциями согласно приведенному выше пункту.Мне кажется, что это означает, что вы должны иметь возможность заменить каждый экземпляр a.back()
на *--a.end()
и наоборот, а код все еще работает.
Согласно Бо Перссону,пересмотренный стандарт C ++, который у меня на руках , имеет дефект относительно таблицы 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()
, и разыменовать уменьшенный итератор до тех пор, покакак это не временно.