Чтение онлайн

ЖАНРЫ

Стандарты программирования на С++. 101 правило и рекомендация

Александреску Андрей

Шрифт:
Примеры

Пример 1. Использование инициализирующего значения по умолчанию или оператора

?:
для снижения степени смешивания потока данных и потока управления.

// Не рекомендуется: не инициализирует переменную

int speedupFactor;

if (condition)

 speedupFactor = 2;

else

 speedupFactor = -1;

//
Лучше: инициализирует переменную

int speedupFactor = -1;

if (condition)

 speedupFactor = 2;

// лучше: инициализирует переменную

int speedupFactor = condition ? 2 : -1;

Варианты, отмеченные как лучшие, не имеют промежутка между определением и инициализацией.

Пример 2. Замена сложных вычислений вызовом функции. Иногда вычисление значения происходит таким образом, что лучше инкапсулировать его в функции (см. рекомендацию 11).

// Не рекомендуется: не инициализирует переменную

int speedupFactor;

if (condition) {

 // ... код ...

 speedupFactor = somevalue;

} else {

 // ... код ...

 speedupFactor = someothervalue;

}

// Лучше: инициализирует переменную

int speedupFactor = ComputeSpeedupFactor;

Пример 3. Инициализация массивов. Для больших составных типов, таких как массивы, корректная инициализация не всегда означает реальное обращение к данным. Пусть, например, вы используете API, который заставляет вас использовать фиксированные массивы char размера

МАХ_РАТН
(см. рекомендации 77 и 78). Если вы уверены, что массивы всегда будут рассматриваться как строки в стиле С с завершающим нулевым символом, то такого немедленного присваивания будет достаточно:

// Допустимо: Создание пустой строки

char path[MAX_PATH];

path[0] = '\0';

Более безопасная инициализация заполняет все элементы массива нулевыми значениями:

// Лучше: заполняем нулями весь массив

char path[MAX_PATH] = { '\0' };

Рекомендованы оба варианта, но в общем случае вы должны предпочитать безопасность излишней эффективности.

Исключения

Входные буферы и данные, описанные как

volatile
, которые записываются непосредственно аппаратным обеспечением или другими процессами, не требуют инициализации программой.

Ссылки

[Dewhurst03] §48 • [Stroustrup00] §4.9.5, §6.3

20. Избегайте длинных функций и глубокой вложенности

Резюме

Краткость — сестра таланта. Чересчур длинные функции и чрезмерно вложенные блоки кода зачастую препятствуют реализации принципа "одна функция —

одна задача" (см. рекомендацию 5), и обычно эта проблема решается лучшим разделением задачи на отдельные части.

Обсуждение

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

Чрезмерно большая по размеру функция и чрезмерная вложенность блоков (например, блоков

if
,
for
,
while
и
try
) делают функции более трудными для понимания и сопровождения, причем зачастую без каких бы то ни было оснований.

Каждый дополнительный уровень вложенности приводит к излишним интеллектуальным нагрузкам при чтении кода, поскольку при этом требуется хранить в памяти "стек" наподобие "вошли в цикл… вошли в блок

try
… вошли в условный оператор… еще в один цикл…". Вам никогда не приходилось продираться сквозь сложный код и искать, какой же именно из множества конструкций
for
,
whilе
и т.п. соответствует вот эта закрывающая фигурная скобка? Более хорошее и продуманное разложение задачи на функции позволит читателю вашей программы одновременно удерживать в голове существенно больший контекст.

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

• Предпочитайте связность. Пусть одна функция решает только одну задачу (см. рекомендацию 5).

• Не повторяйтесь. Следует предпочесть именованную функцию повтору схожих фрагментов кода.

• Пользуйтесь оператором

&&
. Избегайте вложенных последовательных конструкций
if
там, где их можно заменить оператором
&&
.

• Не нагружайте

try
. Предпочитайте использовать освобождение ресурсов в деструкторах, а не в
try
– блоках (см. рекомендацию 13).

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

• Не используйте

switch
для дескрипторов типов. Применяйте вместо этого полиморфные функции (см. рекомендацию 90).

Исключения

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

Ссылки

[Piwowarski82] • [Miller56]

Поделиться с друзьями: