как-будто правило и снятие выделения

«как будто правило«дает компилятору право оптимизировать или переупорядочивать выражения, которые не повлияют на вывод и правильность программы при определенных правилах, таких как;

§1.9.5

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

Ссылка на cppreference, которую я связал выше, специально упоминает специальные правила для значений изменчивых объектов, а также для «новых выражений» в C ++ 14:

У выражения new есть еще одно исключение из правила «как будто»: компилятор
может удалить вызовы к заменяемым функциям выделения, даже если
Определяемая пользователем замена предоставляется и имеет наблюдаемые побочные эффекты.

Я предполагаю, что «заменяемый» вот то, о чем говорится, например, в

§18.6.1.1.2

Заменимый: программа на C ++ может определить функцию с этой функцией
подпись, которая заменяет версию по умолчанию, определенную в C ++
стандартная библиотека.

Это правильно, что mem ниже может быть удален или переупорядочен согласно правилу «как будто»?

  {
... some conformant code // upper block of code

auto mem = std::make_unique<std::array<double, 5000000>>();

... more conformant code, not using mem // lower block of code
}

Есть ли способ убедиться, что он не удален и остается между верхним и нижним блоками кода? На ум приходит хорошо размещенный volatile (или / или volatile std :: array, или left of auto), но поскольку нет чтения memЯ думаю, что даже это не поможет под как будто править.

Примечание; Я не смог заставить визуальную студию 2015 оптимизировать mem и распределение на всех.

Пояснение: путь к наблюдать это может быть связано с тем, что вызов выделения ОС происходит между любыми операциями ввода-вывода из двух блоков. Смысл этого для тестовых случаев и / или попыток получить объекты для размещения в новых местах.

9

Решение

Да; Нет, не в C ++.

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

В абстрактной машине auto mem = std::make_unique<std::array<double, 5000000>>(); создает переменную mem, Это, если используется, дает вам доступ к большому количеству doubles упакован в массив. Абстрактная машина может выдать исключение или предоставить вам такое большое количество doubles; либо в порядке.

Обратите внимание, что это законный компилятор C ++, чтобы заменить все выделения через new с безусловным throw ошибки выделения (или возврата nullptr для версий без бросков), но это было бы плохим качеством реализации.

В случае, когда он выделен, стандарт C ++ не говорит, откуда он. Например, компилятор может использовать статический массив и сделать delete не звоните (обратите внимание, возможно, придется доказать, что он перехватывает все способы вызова delete в буфере).

Далее, если у вас есть статический массив, если никто не читает и не пишет в него (а конструкцию нельзя наблюдать), компилятор может его устранить.


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

Таким образом, подход состоит в том, чтобы компилятор не мог знать об этом. Ваш код загружает DLL, а затем передает указатель на unique_ptr в эту DLL в тех местах, где вы хотите, чтобы ее состояние было известно.

Поскольку компилятор не может оптимизировать вызовы DLL во время выполнения, состояние переменной должно в основном соответствовать ожидаемому.

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

Упомянутая DLL может быть отдельно написана, чтобы быть noop; или, даже, вы можете проверить некоторое внешнее состояние, и условно загрузить и передать данные в DLL на основе внешнего состояния. Пока компилятор не может доказать, что произойдет указанное внешнее состояние, он не может оптимизировать вызовы не Быть сделанным. Тогда никогда не устанавливайте это внешнее состояние.

Объявите переменную в верхней части блока. Передайте указатель на него в fake-external-DLL, пока он не инициализирован. Повторите только перед инициализацией, затем после. Затем, наконец, сделайте это в конце блока, прежде чем уничтожить его, .reset() это, затем сделай это снова.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]