Трюки от Криса
Хакер, номер #093, стр. 093-146-2 В итоге, мы получим более тормозной и громоздкий код, что есть минус. Но зато теперь можно забыть про фрагментацию кучи, что есть плюс. По ссылке или по значению Язык Си поддерживает два способа передачи переменных — по ссылке и по значению, порождая тем самым извечную проблему выбора. Программистское сообщество разбилось на два больших лагеря, отстаивающих свои взгляды на дизайн программирования, и ожесточенно воющих между собой. Один лагерь говорит: все, что помещается в регистр общего назначения (то есть, физически представляет собой байт, слово или двойное слово) передается по значению, остальное — по ссылке, потому что так гораздо быстрее и требует меньше памяти. Другой лагерь с этим категорически не согласен: кому сейчас нужна быстрота? А потребности в памяти всегда может удовлетворить новый DIMM. Передача переменных по ссылке потенциально опасна и вносит большую сумятицу, поскольку при передаче по значению функции передается копия переменной, которую она может модифицировать как угодно, не затрагивая оригинал. А вот при передаче по ссылке возникает угроза непреднамеренной порчи данных, кроме того при чтении листинга становится непонятно то ли мы просто передаем значение функции, то ли принимает через эту возвращенный результат. Формально, запретить модификацию переменной, переданной по ссылке можно через квалификатор const, однако, надежной такую защиту не назовешь, поскольку const легко обходится через преобразование типов (как преднамеренное, так и нет). С другой стороны, передавать большие объемы данных по значению смерти подобно, особенно в рекурсивных функциях или при глубоком объеме вложенности. Выход — передаем переменные по ссылке, для наглядности предварив их const, а на физическом уровне защитив от модификации вызовом VirtualProtect(,,PAGE_READONLY,). Естественно, при выходе из функции защиту необходимо восстановить. Пользователи коммерческих компиляторов (вроде Microsoft Visual C++) вынуждены делать это вручную (что чревато ошибками), а вот GCC, бесплатно распространяемый в исходных текстах, позволяет свободно модифицировать пролог и эпилог каждой функции по своему усмотрению. Кстати говоря, здесь мы снова сталкиваемся с невозможностью реализации данного механизма в многопоточных программах, поскольку в то время пока одна функция "защитила" переменную, никакая другая функция чужого потока не может ее менять, даже если ей это действительно необходимо. Одно из главных достоинств UNIX'а как раз и заключается в том, что в нем потоки играют второстепенную роль и вообще говоря не слишком популярны. А вот в Windows… задачи синхронизации приходится решать вручную. Как говорится, создавая потоки, мы создаем себе проблемы, но это уже тема для другого разговора. |