Подтвердить что ты не робот

Май std::vector использует небольшую оптимизацию буфера?

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

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

Вначале кажется, что он запрещает оптимизацию небольших буферов, но в соответствии с правилом as-if нам будет разрешено выполнять небольшую оптимизацию буфера для типов неклассов (поскольку мы не можем наблюдать за выполняемой копией). Следующий текст кажется сложнее "обмануть"

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

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

4b9b3361

Ответ 1

23.2.1/p10/b6:

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

  • Функция
  • no swap() делает недействительными любые ссылки, указатели или итераторы, ссылающиеся на элементы обменяемых контейнеров....

Нигде он не указывает "иначе" для vector. Таким образом, это запрещает SBO для vector.

string не связан этим правилом, потому что он "указывает иначе" в 21.4.1/p6:

Ссылки, указатели и итераторы, относящиеся к элементам basic_string может быть признана недействительной следующими способами использования этого Объект basic_string:

  • как аргумент любой стандартной библиотечной функции, ссылающейся на не-const basic_string в качестве аргумента. ^ 234

234) Например, в качестве аргумента для функций, не являющихся членами, swap() (21.4.8.8), оператор → () (21.4.8.9) и getline() (21.4.8.9) или как аргумент basic_string:: swap()

Ответ 2

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

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

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