Oct 23

Начнем издалека… Есть в C++ встроенный тип size_t, который является “целым типом без знака, используемым реализацией для индексирования массивов” © Страуструп. То есть, если вы работаете с индексами в массивах и их длинами, то в общем-то “правильнее” использовать не int, что в большинстве случаев и делается, а именно size_t (для длин можно еще использовать ptrdiff_t - тип, который возвращает операция вычитания двух указателей). Вчера эта “правильность” для меня вышла боком…

size_t length; 
... 
for(size_t i = 0; i < length; ++i) { 
    double x = 2 * (i - length / 2) / length; 
    ... 
}

Вот такой был изначальный код. Через несколько минут после написания я вспомнил, что неплохо бы сделать так:

size_t length; 
... 
for(size_t i = 0; i < length; ++i) { 
    double x = 2 * static_cast<double>(i - length / 2) / length; 
    ... 
}

потому что при делении двух целых чисел у нас тоже целое будет, а мне нужно было как раз вещественное.

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

size_t length; 
... 
for(size_t i = 0; i < length; ++i) { 
    double x = 2 * static_cast<double>(static_cast<int>(i) - static_cast<int>(length) / 2) / length; 
    ... 
}

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

Выводы: или пишите не особо заморачиваясь на правильности употребления типов (везде используйте int и double, например), или пишите семантически правильно, но не делайте таких ошибок, как я… Может, конечно, это только я такой, но мне лично сложно было именно по коду определить, что результат будет получаться не такой как я хочу.

PS. Я теперь немного понимаю, почему в Java нет unsigned типов. :) 

written by fxposter \\ tags:


2 Responses to “Немного об ошибках в C++”

  1. 1. Евгений Says:

    Не хочу расстраивать, но вместо
    2 * static_cast(i – length / 2) / length;
    достаточно написать
    2.0 * (i – length / 2) / length
    А вообще static_cast используется для безопасного приведения классов. Для базовых типов смело можно писать (int)i-int(length/2). Уж тут-то компилятор справиться, можно не переживать :-)

  2. 2. Александр Says:

    А индекс минус размер в итоге даёт индекс или всё-таки размер? Т.е. как бы нам от 3 помидоров отнять 2 огурца и получить 1 тыкву…. поэто без “кастов” не обошлось… :-) Проблема не в типах, а в некорректном их применении, что в данном случае и произошло. Пересмотрите выводы.

Leave a Reply