утверждать (ложно) на языке D - PullRequest
6 голосов
/ 06 августа 2011

TDPL описывает поведение оператора assert(false);.Такое утверждение не удаляется из сборки выпуска (как и все другие утверждения) и фактически останавливает программу немедленно.Вопрос почему?Почему такое запутанное поведение?Они могут добавить halt(); или что-то подобное, чтобы иметь возможность остановить программу.

Иногда я использую следующую конструкцию в коде C ++:

if (something_goes_wrong)
{
   assert(false);
   return false;
}

Очевидно, такая конструкциявозможно в D.

ОБНОВЛЕНИЕ

Для ясности.Вопрос в том, почему int x=0; assert(x); не будет аварийно завершать выпуск версии программы, а assert(0); будет?Почему такое странное языковое дизайнерское решение?

Ответы [ 3 ]

8 голосов
/ 06 августа 2011

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

типичное использованиеэто так

MyStruct foo(){
    foreach(s;set){
        if(someConditionGuaranteedToHoldForAtLeastOne(s))
            return s;
    }
    //now what I can't return null;
    assert(0);//tell the compiler I don't expect to ever come here
}
7 голосов
/ 07 августа 2011

Утверждение используется для проверки чего-либо о состоянии вашей программы в определенный момент программы. Если утверждение не выполняется, значит, в программе есть ошибка, и нет смысла продолжать выполнение программы. Но стоит что-то стоит для запуска утверждения - особенно если оно включает вызовы функций - поэтому вы обычно отключаете их в режиме выпуска (-release для dmd делает это автоматически). Вы запускаете свою программу и тестируете ее в режиме отладки, и, надеюсь, вы попадете в любые состояния, которые приводят к сбоям утверждений, чтобы вы могли отследить и исправить эти ошибки. Тогда вы надеетесь, что поймали их всех и что в режиме релиза ничего страшного не произойдет, если вы этого не сделали.

Но как насчет ввода путей кода, которые никогда не должны быть достигнуты при любых обстоятельствах? Вот тут и приходит assert(0).

Он работает как обычное утверждение без -release, так что вы получите хорошие следы стека и все такое, когда вы нажмете на него, но потому что это то, что должно не только никогда не происходить, но и приводить к совершенно неверному пути кода, оно остается в режиме освобождения, но изменился на инструкцию по остановке. Классические места, где его можно использовать, например,

switch(var)
{
    ...
    //various case statements that should cover all possible values of var
    ...

    default:
        assert(0, format("Invalid value for var: %s", var));
}

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

string func(int i) nothrow
{
    try
        return format("%s", i);
    catch(Exception e)
        assert(0, "Format threw. That should be impossible in this case.");
}

, где, если логика func верна, для него должно быть невозможно выбросить, но это вызвало функцию, которую может выбросить при некотором наборе обстоятельств (только не этих), поэтому вы должны использовать блок try-catch, чтобы сделать компилятор счастливым. Затем вы кладете assert(0) в блок catch, чтобы поймать его, если он действительно может throw.

Классический случай для assert(0) фактически используется самим компилятором - то есть вставлять его в конец функции, которая не заканчивается оператором return, чтобы выполнение кода не пытается продолжить, если логика вашего кода неверна и вы все равно каким-то образом оказались в конце функции.

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

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

6 голосов
/ 07 августа 2011

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

"false" никогда не проходит.

...