“Пустая основная оптимизация” в настраивающемся GCC?

Порядок, в котором For Each выполняет итерацию коллекции объектов, зависит от реализации (я обвиняю Excel, а не VBA) и, хотя и, вероятно, детерминирован & amp; предсказуемо, в его спецификации нет ничего, что гарантировало бы определенный порядок итераций. Поэтому код VBA, написанный для итерации коллекции объектов, не должен быть написан с предположением о конкретном порядке итерации, поскольку это то, что может очень хорошо меняться в зависимости от версии используемой библиотеки типов (в данном случае Excel).

Очень неясно, какова форма ваших Range / Selection, но если вам нужно перебрать выбранные ячейки в определенном порядке, то цикл For Each не должен использоваться, по крайней мере, не для перебора. клетки как таковые.

Так как диапазоны не являются смежными, Range будет иметь кратные Areas; вам нужно будет выполнить итерации Selection.Areas и для каждой выбранной области, итерировать ячейки в определенном порядке. For Each, безусловно, является наиболее эффективным способом итерации коллекции объектов , которой является Range.Areas.

Debug.Assert TypeOf Selection Is Excel.Range

Dim currentArea As Range
For Each currentArea In Selection.Areas
    'todo
Next

Вместо того, чтобы вкладывать циклы , создайте отдельную процедуру, которая принимает currentArea в качестве параметра - в этой процедуре вы будете повторять отдельные ячейки:

[111 ]

Теперь внешний цикл выглядит следующим образом:

Debug.Assert TypeOf Selection Is Excel.Range

Dim currentArea As Range
For Each currentArea In Selection.Areas
    ProcessContiguousArea currentArea
Next

Процедура ProcessContiguousArea свободна делать все, что нужно, с данной смежной областью, используя цикл For для итерации диапазон по строкам без необходимости заботиться о фактическом адресе выбранной области: при использовании Range.Cells(RowIndex, ColumnIndex) строка 1 / столбец 1 представляет верхнюю левую ячейку этого диапазона, независимо от того, где этот диапазон находится на рабочем листе. [1130 ]

Невыбранные ячейки могут быть доступны с помощью Range.Offset:

        Debug.Print area.Cells(currentRow, 1).Offset(ColumnOffset:=10).Address

Строка верхней левой ячейки area на рабочем листе возвращается с помощью area.Row, а верхняя левая Столбец ячейки area на рабочем листе извлекается с помощью area.Column.

9
задан Thomas Bonini 26 April 2010 в 12:54
поделиться

3 ответа

Это всегда происходит. Я сразу отправляю, прежде чем я пойму это. Возможно, действие регистрации получает меня думающий по-другому..

Таким образом в моем вопросе образец был немного упрощен. Это на самом деле больше похоже на это:

struct Base {};
struct C1 : Base { int i; }
struct C2 : Base { C1 c; int i; }

sizeof (C1) правильно 4 на всех платформах, но sizeof (C2) 9 вместо 8 на GCC. И... по-видимому, GCC является единственной вещью, которая разбирается в нем, согласно последнему биту статьи, с которой я связался в исходном вопросе. Я заключу его в кавычки (от Nathan Meyers) здесь:

Вся семья связанной "пустой подобъектной" оптимизации возможна согласно спецификациям ABI, которые должен наблюдать компилятор. (Jason Merrill указал на некоторые из них мне, годы назад.), Например, считайте трех членов структуры (пустых) типов A, B, и C и четверть непустыми. Они могут, conformingly, все занимают тот же адрес, пока у них нет оснований друг вместе с другом или с содержанием класса. Общий глюк на практике должен иметь первое (или только) член класса, полученного из той же пустой основы как класс. Компилятор должен вставить дополнение так, чтобы у них два подобъекта были различные адреса. Это на самом деле происходит в адаптерах итератора, которые имеют interator участника, оба полученные из станд.:: итератор. Неосторожно реализованный стандартный станд.:: reverse_iterator мог бы показать эту проблему.

Так, несоответствие, которое я видел, было только в случаях, где у меня был вышеупомянутый шаблон. Любое место, которое я получал из пустой структуры, было в порядке.

Достаточно легкий работать вокруг. Спасибо все для комментариев и ответов.

11
ответ дан 4 December 2019 в 15:26
поделиться

Ну, это не полный ответ, но Руководство GCC упоминает, что g ++ может иногда помещать пустые базовые классы при неправильном смещении. Посмотрите бит о -Wabi опция.

0
ответ дан 4 December 2019 в 15:26
поделиться

GCC C ++ следует этим правилам со стандартным заполнением:

ПРИМЕЧАНИЕ: __ атрибут __ ((__ упаковано __)) или изменение упаковки по умолчанию приведет к изменению этих правил.

  • class EmptyBase {}; -> sizeof (EmptyBase) == 1

  • Любое количество пустых баз будет отображаться в 0 в смещении структуры, если все они являются уникальными типами (включая родительские).

  • Родители с непустой базой просто находятся в порядок, объявленный только с заполнением для выравнивания.

  • Если первый член производного класса, следующий сразу за пустыми базами, не является производным от какой-либо из этих баз, разрешается начать с первого правильно выровненного смещения для этого члена, который больше или равно адресу пустой базы - это может быть тот же адрес, что и адрес пустой базы.

  • Если первый член производного класса, который следует сразу за пустыми базами, действительно является производным от любой из этих баз, он начнется с первого правильно выровненного смещения для этого члена, которое больше, чем адрес пустой базы - это никогда не совпадает с адресом пустых баз.

  • Члены, которые являются пустыми классами, занимают по крайней мере один байт памяти в содержащем классе.


MSVC ++ следует этим правилам:

ПРИМЕЧАНИЕ: #pragma pack или изменение упаковки по умолчанию приведет к изменению этих правил.

  • class EmptyBase {}; -> sizeof (EmptyBase) == 1

  • Единственный способ, которым класс с пустой базой (или класс, производный от пустой базы) будет начинаться со смещения 0 (ноль), - это если это первый базовый класс.

  • Непустой базовый класс начнется со следующего допустимого смещения выравнивания для базового класса.

  • Все классы с пустой базой будут иметь нулевое эффективное хранилище в производном классе и не будут влиять на текущее смещение, если за ними не последует другой класс с пустой базой (или класс, производный от пустой базы), и в этом случае вы должны увидеть следующее правило.

  • Класс с пустой базой (или класс, производный от пустой базы), который следует за классом с пустой базой (или класс, производный от пустой базы), добавит 1 к текущей позиции смещения перед заполнением до правильное выравнивание для класса.

  • Нет никаких отступов (кроме выравнивания) между последним базовым классом и первым членом класса или указателем (ами) vft. *** ПРИМЕЧАНИЕ: это чрезмерно агрессивная оптимизация пустой базы, которая может нарушить стандарт C ++.

  • Члены, которые являются пустыми классами, занимают по крайней мере один байт памяти в содержащем классе.

2
ответ дан 4 December 2019 в 15:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: