Может ли std::vector использовать небольшую буферную оптимизацию?
Мне было интересно с моим коллегой сегодня, можно ли реализовать std::vector, чтобы использовать небольшую оптимизацию буфера. Посмотрев на черновик C++11, я прочитал 23.3.1p8
Выражение a.swap(b) для контейнеров a и b стандартного типа контейнера, кроме массива, должно обмениваться значениями a и b без вызова каких-либо операций перемещения, копирования или обмена для отдельных элементов контейнера.
На первый взгляд кажется, что оптимизация небольшого буфера запрещена, но в соответствии с правилом "как будто" нам будет разрешено выполнять небольшую оптимизацию буфера для не относящихся к классу типов (поскольку мы не можем наблюдать, как выполняется копирование). Следующий текст кажется труднее "обмануть"
Каждый итератор, ссылающийся на элемент в одном контейнере до обмена, должен ссылаться на тот же элемент в другом контейнере после обмена.
Достаточно ли этого, чтобы предотвратить реализацию оптимизации небольшого буфера для std::vector? Существуют ли какие-либо другие препятствия или возможно получить std::vector с SBO?
2 ответа
23.2.1 / p10 / b6:
Если не указано иное...
- никакая функция swap () не делает недействительными какие-либо ссылки, указатели или итераторы, ссылающиеся на элементы переставляемых контейнеров....
Нигде это не "указывает иначе" для vector
, Так что это запрещает SBO для vector
,
string
не ограничен этим правилом, потому что он "указывает иначе" в 21.4.1/p6:
Ссылки, указатели и итераторы, ссылающиеся на элементы последовательности basic_string, могут быть признаны недействительными из-за следующего использования этого объекта basic_string:
- в качестве аргумента любой стандартной библиотечной функции, принимающей в качестве аргумента ссылку на неконстантную basic_string. ^ 234
234) Например, в качестве аргумента для функций, не являющихся членами swap() (21.4.8.8), operator>>() (21.4.8.9) и getline() (21.4.8.9) или в качестве аргумента для basic_string::своп()
В дополнение к проблеме с аннулированием итератора, есть аргумент безопасности, позволяющий избежать оптимизации небольшого буфера.
Если пишет переполнить std::vector
вы получаете повреждение кучи, что довольно сложно предсказать, что будет перезаписано, и очень трудно использовать для выполнения произвольного кода.
Если буфер вместо этого встроен в локальную переменную, переполнение уничтожает стек, и злоумышленник, вероятно, получит контроль над обратным адресом, что гораздо более полезно (например, атаки return-to-libc).