Когда сознательное использование неопределенного поведения приносит пользу, не жертвуя правильностью?

Я начну с предыстории используемых терминов.

Правильный

«В теоретической информатике правильность алгоритма утверждается, когда говорят, что алгоритм корректен по отношению к спецификации». — тег корректности при переполнении стека.

Неопределенный

Неопределенное поведение — это где что-нибудь позволено случиться. По сути, возможности того, что может произойти, безграничны. Примерами являются разыменование nullptr в C ++ и деление на ноль.

Вполне определенный

Здесь возможен один-единственный результат.

Реализация определена

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

Неопределенные

Это где больше, чем один, но меньше, чем бесконечное количество возможностей.

Использование неопределенного поведения

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

Идея

Здесь вещи становятся интересными. Или, по крайней мере, потенциал есть. Это серая область программирования. Существует некоторое представление о том, что может или не может произойти, но то, что происходит, не является ни четко определенным, ни неопределенным.

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

Где еще сознательная реализация неопределенного поведения приносит пользу, не жертвуя правильностью? Там должно быть какое-то преимущество.

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

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

2

Решение

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

Обратите внимание, что в C ++ использование неопределенного значения является неопределенным поведением только для unsigned char; для всех других типов это было бы неопределенным поведением. См. Раздел 8.5 стандарта для получения дополнительной информации.

3

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

Неуказанное поведение не предназначено для программиста (наоборот, если программист знает, что нужно с осторожностью смотреть и избегать), неуказанное поведение, как и все остальные: неопределенное, определенная реализация и т. Д … для автора компилятора, чтобы использовать в своих интересах (например, Порядок оценки подвыражений имеют неопределенное поведение, для этого вам не следует передавать в оценках никакое подвыражение с побочными эффектами, и, если вы позаботитесь об этом, компилятор переупорядочит оценку подвыражения как можно более эффективную, некоторые подвыражения могут содержать те же вычисления, которые могут быть использованы повторно, и многие другие оптимизации могут воспользоваться знаниями, которые могут быть оценены в лучшем порядке, который он может найти.

2

Единственный случай, который приводит к программе с детерминированным поведением, — это случай, когда независимо от того, какую из возможностей использует реализация, результат один и тот же.

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

1

Я сделал «очень полезную» программу, которая говорит вам, первый или второй операнд + в выражении foo() + bar() оценивается первым при запуске программы:

#include <iostream>

bool done = false;

int foo() {
if (!done) {
std::cout << "First operand evaluated first" << std::endl;
done = true;
}
return 0;
}

int bar() {
if (!done) {
std::cout << "Second operand evaluated first" << std::endl;
done = true;
}
return 0;
}

int main()
{
foo() + bar();
}

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

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

0

Я не умный ученый в области ракетостроения. Мне ваш вопрос

1) .. не имеет смысла для C ++

В традиционном программировании, которое большинство читателей Stack Overflow делают ежедневно, нам просто нужно, чтобы вещи были определены и вели себя детерминистическим и предсказуемым образом, в результате чего работало программное обеспечение — http://en.wikipedia.org/wiki/Deterministic_Turing_machine. И если это сработало сегодня, мы хотим, чтобы и сработало завтра

C ++ также попадает в эту категорию

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

2) .. имеет смысл в аппаратно-ориентированных языках

в VHDL программисты на языке программирования используют (работают с) специальные переменные состояния (см. Какова цель перечислимого типа `std_logic` в VHDL?) представляет значение сигнала, которое не известно как провод, несущий сигнал, не подключен. Резать. Unplugged. белый шум и т.п.

3) .. имеет смысл вне традиционного мира процессоров

Существует целая вычислительная вселенная, в которой термины «неопределенный» и «неопределенный» и т. Д. Полностью вступают в игру. И это http://en.wikipedia.org/wiki/Quantum_computer.

Google инвестирует в исследования квантовых вычислений и компания, которая работает над этим D-Wave Systems Inc.

Но это действительно смена парадигмы (похоже на программирование Нано компьютеры)


Таким образом, мой средний-IQ-ответ либо сделает ваш вопрос полезным для C ++, либо переместит его на более подходящий сайт Stack Exchange (например, https://cs.stackexchange.com/) или утолить жажду за пределами C ++ парадигма программирования

0

Неясно, какую из двух вещей вы спрашиваете:

  1. В ситуациях, когда Стандарт указывает, что компилятор может выбирать из нескольких возможных вариантов поведения произвольным образом, но когда какой-то конкретный компилятор всегда использует одну и ту же альтернативу, может ли пользовательский код с пользой использовать такое поведение компилятора, хотя и не определено,?

  2. В ситуациях, когда Стандарт позволяет компилятору выбирать из нескольких возможных вариантов поведения, и когда различные варианты поведения будут иметь разные результаты, может ли программа, чей вывод будет зависеть от неуказанного поведения, считаться «правильной», если любой возможный вывод, произведенный таким поведением, будет Удовлетворять потребности?

Я бы настоятельно рекомендовал не полагаться на усмотрение компилятора в отношении последовательности, в которой оцениваются различные части выражения. Если цикл развернут, вполне вероятно, что некоторые операторы внутри цикла могут иногда оцениваться так или иначе. Хотя бывают случаи, когда удобно говорить int x = getc()+256*getc(); отсутствие какой-либо гарантии согласованности относительно того, будет ли умножен первый или второй символ, делает такие конструкции довольно бесполезными.

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

0