Накладные расходы переменной длины в С++?
Глядя на этот вопрос: Почему компилятору C/С++ нужно знать размер массива во время компиляции?, мне пришло в голову, что разработчики компилятора должны были несколько раз, чтобы получить свои ноги теперь (это часть стандарта C99, что 10 лет назад) и обеспечивают эффективные реализации.
Однако по-прежнему кажется (из ответов) считаться дорогостоящим.
Это меня как-то удивляет.
Конечно, я понимаю, что статическое смещение намного лучше, чем динамическое с точки зрения производительности, и, в отличие от одного предложения, я бы не имел на самом деле компилятор, выполняющий распределение кучи массива, поскольку это, вероятно, стоило бы еще больше [ это не было измерено;)]
Но я все еще удивляюсь предполагаемой стоимости:
- если в функции нет VLA, тогда не было бы никакой стоимости, насколько я могу видеть.
- если есть один единственный VLA, тогда можно либо поместить его перед или после всех переменных, и, следовательно, получить статическое смещение для большей части фрейма стека (или, как мне кажется, но я не хорошо разбираюсь в управлении стеком)
Возникает вопрос о нескольких VLA, конечно, и мне было интересно, будет ли работать выделенный VLA-стек. Это означает, что VLA будет отображаться счетчиком и указателем (из известных размеров), а фактическая память, взятая во вторичном стеке, используется только для этой цели (и, следовательно, действительно является стеком).
[перефразировать]
Как VLAs реализованы в gcc/VС++?
Действительно ли это действительно впечатляет?
[end rephrasing]
Мне кажется, что это может быть лучше, чем использование, скажем, vector
, даже с существующими реализациями, поскольку вы не несете затраты на динамическое размещение (за счет того, что не изменяете размер).
EDIT:
Существует частичный ответ здесь, однако сравнение VLA с традиционными массивами кажется несправедливым. Если бы мы знали размер заранее, то нам не понадобилось бы VLA. В том же вопросе AndreyT дал некоторые указания относительно реализации, но это не так точно, как хотелось бы.
Ответы
Ответ 1
Как VLAs реализованы в gcc/VС++?
AFAIK VС++ не реализует VLA. Это компилятор С++ и поддерживает только C89 (без VLA, без ограничений). Я не знаю, как gcc реализует VLA, но самым быстрым способом является сохранение указателя на VLA и его размер в статической части стекового кадра. Таким образом, вы можете получить доступ к одному из VLA с производительностью массива с постоянным размером (это последний VLA, если стек растет вниз, как в x86 (разыменование [указатель стека + индекс * размер элемента + размер последних временных нажатий]), и первый VLA, если он растет вверх (разыменование [указатель стека/смещение от размера стека/рамки + индекс *))). Все остальные VLA нуждаются в еще одном обращении, чтобы получить свой базовый адрес из статической части стека.
[Редактировать: также при использовании VLA компилятор не может опустить указатель на стек-фрейм, который в противном случае лишний, поскольку все смещения от указателя стека могут быть вычислены во время компиляции. Итак, у вас есть один бесплатный бесплатный реестр. — end edit]
Действительно ли это действительно впечатляет?
Не совсем. Более того, если вы не используете его, вы не платите за него.
[Edit: Возможно, более правильным ответом будет: По сравнению с чем? По сравнению с выделенным кучей вектором время доступа будет таким же, но распределение и освобождение будут быстрее. — end edit]
Ответ 2
Если бы это было реализовано в VС++, я бы предположил, что команда компилятора использует некоторый вариант _alloca(size)
. И я думаю, что стоимость эквивалентна использованию переменных с более чем 8-байтовым выравниванием в стеке (например, __m128
); компилятор должен где-то хранить исходный указатель стека, а для выравнивания стека требуется дополнительный регистр для хранения неуравновешенного стека.
Таким образом, накладные расходы в основном являются дополнительным направлением (вы должны где-то хранить адрес VLA) и регистрировать давление из-за хранения исходного диапазона стека где-то также.