Может ли 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).

Другие вопросы по тегам