Может ли std :: vector использовать небольшую буферную оптимизацию? - PullRequest
48 голосов
/ 19 ноября 2011

Мне было интересно с моим коллегой сегодня, можно ли реализовать std :: vector, чтобы использовать небольшую оптимизацию буфера. Изучая черновик C ++ 11, я прочитал 23.3.1p8

Выражение a.swap (b) для контейнеров a и b стандартного типа контейнера, отличного от массива, должно обмениваться значениями a и b без вызова каких-либо операций перемещения, копирования или обмена для отдельных элементов контейнера.

На первый взгляд кажется, что оптимизация небольших буферов запрещена, но в соответствии с правилом «как будто» нам будет разрешено выполнять оптимизацию небольших буферов для типов, не относящихся к классам (поскольку мы не можем наблюдать, как выполняется копирование). Следующий текст кажется труднее «обмануть»

Каждый итератор, ссылающийся на элемент в одном контейнере до обмена, должен ссылаться на тот же элемент в другом контейнере после обмена.

Достаточно ли этого, чтобы предотвратить реализацию оптимизации небольшого буфера для std :: vector? Существуют ли какие-либо другие препятствия или возможно получить std :: vector с SBO?

Ответы [ 2 ]

47 голосов
/ 19 ноября 2011

23.2.1 / p10 / b6:

Если не указано иное ...

  • no 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 :: swap ()

1 голос
/ 29 декабря 2012

В дополнение к проблеме с аннулированием итератора, есть аргумент безопасности, позволяющий избежать оптимизации небольшого буфера.

Если запись перезапускает std::vector, вы получаете повреждение кучи, что довольно сложно предсказать, что перезаписывается, и очень трудно использовать для выполнения произвольного кода.

Если буфер вместо этого встроен в локальную переменную, переполнение уничтожает стек, и злоумышленник, вероятно, получит контроль над обратным адресом, что гораздо полезнее (например, атака с возвратом в libc).

...