Правило 26: Откладывайте определение переменных насколько возможно

Правило 26: Откладывайте определение переменных насколько возможно

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

Вероятно, вы думаете, что никогда не объявляете неиспользуемых переменных, но так ли это? Рассмотрим следующую функцию, которая возвращает зашифрованный пароль при условии, что его длина не меньше некоторого минимума. Если пароль слишком короткий, функция возбуждает исключение типа logic_error, определенное в стандартной библиотеке C++ (см. правило 54):

// эта функция объявляет переменную encrypted слишком рано

std::string encryptPassword(const std::string& password)

{

using namespace std;

string encrypted;

if(password.length() < MinimumPasswordLength) {

throw logic_error(“Слишком короткий пароль”);

}

... // сделать все, что необходимо для помещения

// зашифрованного пароля в переменную encrypted

return encrypted;

}

Нельзя сказать, что объект encrypted в этой функции совсем уж не используется, но он не используется в случае, когда возбуждается исключение. Другими словами, вы платите за вызов конструктора и деструктора объекта encrypted, даже если функция encryptPassword возбуждает исключение. Так не лучше ли отложить определение переменной encrypted до того момента, когда вы будете знать, что она нужна?

// в этой функции определение переменной encrypted отложено до момента,

// когда в ней возникает надобность

std::string encryptPassword(const std::string& password)

{

using namespace std;

if(password.length() < MinimumPasswordLength) {

throw logic_error(“Слишком короткий пароль”);

}

string encrypted;

... // сделать все, что необходимо для помещения

// зашифрованного пароля в переменную encrypted

return encrypted;

}

Этот код все еще не настолько компактный, как мог бы быть, потому что переменная encrypted определена без начального значения. А значит, будет использован ее конструктор по умолчанию. Часто первое, что нужно сделать с объектом, – это дать ему какое-то значение, нередко посредством присваивания. В правиле 4 объяснено, почему конструирование объектов по умолчанию с последующим присваиванием значения менее эффективно, чем инициализация нужным значением с самого начала. Это относится и к данному случаю. Например, предположим, что для выполнения «трудной» части работы функция encryptPassword вызывает следующую функцию:

void encrypt(std::string& s); // шифрует s по месту

Тогда encryptPassword может быть реализована следующим образом, хотя и это еще не оптимальный способ:

// в этой функции определение переменной encrypted отложено до момента,

// когда в ней возникает надобность, но и этот вариант еще недостаточно

// эффективен

std::string encryptPassword(const std::string& password)

{

... // проверка длины

string encrypted; // конструктор по умолчанию

encrypted = password; // присваивание encrypted

encrypt(encrypted);

return encrypted;

}

Еще лучше инициализировать encrypted параметром password, избежав таким образом потенциально дорогостоящего конструктора по умолчанию:

// а это оптимальный способ определения и инициализации encrypted

std::string encryptPassword(const std::string& password)

{

... // проверка длины

string encrypted(password); // определение и инициализация

// конструктором копирования

encrypt(encrypted);

return encrypted;

}

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

«А как насчет циклов?» – можете удивиться вы. Если переменная используется только внутри цикла, то что лучше: определить ее вне цикла и выполнять присваивание на каждой итерации или определить ее внутри цикла? Другими словами, какая из следующих конструкций предпочтительнее?

// Подход A: определение вне цикла

Widget w;

for(int i=0; i<n; ++i) {

w = некоторое значение, зависящее от i;

...

}

// Подход B: определение внутри цикла

for(int i=0; i<n; ++i) {

Widget w(некоторое значение, зависящее от i);

...

}

Здесь я перехожу от объекта типа string к объекту типа Widget, чтобы избежать любых предположений относительно стоимости конструирования, разрушения и присваивания.

В терминах операций Widget накладные расходы вычисляются так:

• Подход A: 1 конструктор + 1 деструктор + n присваиваний

• Подход B: n конструкторов + n деструкторов

Для классов, в которых стоимость операции присваивания меньше, чем пары конструктор-деструктор, подход A обычно более эффективен. Особенно это верно, когда значение n достаточно велико. В противном случае, возможно, подход B лучше. Более того, в случае A имя w видимо в более широкой области (включающей в себя цикл), чем в случае B, а иногда это делает программу менее понятной и удобной для сопровождения. Поэтому если (1) нет априорной информации о том, что присваивание обходится дешевле, чем пара конструктор-деструктор, и (2) речь идет о части программы, производительность которой критична, то по умолчанию рекомендуется использовать подход B.

Что следует помнить

• Откладывайте определение переменных насколько возможно. Это делает программы яснее и повышает их эффективность.

Данный текст является ознакомительным фрагментом.



Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

2.1. Насколько ресурсоемко архивирование HTML

Из книги автора

2.1. Насколько ресурсоемко архивирование HTML Архивирование (gzip-, deflate-сжатие) уже давно является наиболее известной техникой оптимизации. Однако применяют ее по-прежнему так же редко, как и 10 лет назад. Я постараюсь максимально подробно осветить проблемные аспекты


Взгляд Optimism.ru на SEO: насколько полон стакан?

Из книги автора

Взгляд Optimism.ru на SEO: насколько полон стакан? Открыть сегодня SEO — агентство – инфантильная студенческая мечта или, напротив, зрелая мысль человека, который не гонится за сверхприбылью и готов сфокусироваться на каком — то одном направлении оптимизации? Об успешном опыте


Враг может нанять хакера. Насколько это опасно и как с этим бороться?

Из книги автора

Враг может нанять хакера. Насколько это опасно и как с этим бороться? Это серьезный аспект информационной войны в Интернете, который нельзя обойти молчанием. Начиная противодействие агрессору в Интернете, вы ломаете своими действиями его планы, делаете неэффективными


Насколько быстро нужно отвечать?

Из книги автора

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


13 Сложность: просто, как только возможно, но не проще

Из книги автора

13 Сложность: просто, как только возможно, но не проще Все следует делать так просто, как только возможно, но не проще. —Альберт Эйнштейн В конце главы 1 философия Unix была сведена к общему принципу — K.I.S.S. (Keep It Simple, Stupid! Будь проще!). В части "Проектирование" данной книги одной


13 Сложность: просто, как только возможно, но не проще

Из книги автора

13 Сложность: просто, как только возможно, но не проще Все следует делать так просто, как только возможно, но не проще. —Альберт Эйнштейн В конце главы 1 философия Unix была сведена к общему принципу — K.I.S.S. (Keep It Simple, Stupid! Будь проще!). В части "Проектирование" данной книги одной


ОПРЕДЕЛЕНИЕ СТРУКТУРНЫХ ПЕРЕМЕННЫХ

Из книги автора

ОПРЕДЕЛЕНИЕ СТРУКТУРНЫХ ПЕРЕМЕННЫХ      Слово "структура" используется двояко. Во-первых, в смысле "структурного шаблона", о котором мы только что рассказали. Шаблон является схемой без содержания; он сообщает компилятору, как делать что-либо, но нс вызывает никаких


Определение переменных и понятие о них

Из книги автора

Определение переменных и понятие о них Во всех современных языках программирования, в том числе в Objective-C, существуют переменные. Переменные — это просто псевдонимы, обозначающие участки (местоположения) в памяти. Каждая переменная может иметь следующие свойства:тип


БЕЗОПАСНОСТЬ: Если возможно, значит, нужно

Из книги автора

БЕЗОПАСНОСТЬ: Если возможно, значит, нужно Автор: Киви БердВ сводках хайтек-новостей Польша редкая гостья, но недавно наша соседка привлекла к себе внимание, выступив с интересной инициативой в области внедрения полицейских технологий. Одна из крупнейших в этой стране


Возможно ли взломать ЭЦП?

Из книги автора

Возможно ли взломать ЭЦП? Взлом ЭЦП фактически сводится к взлому алгоритма шифрования. В данном случае возможные варианты взлома мы рассмотрим на примере алгоритма RSA.Существует несколько способов взлома RSA. Наиболее эффективная атака – найти секретный ключ,


Насколько глупа шумиха вокруг «умных» часов? Андрей Письменный

Из книги автора

Насколько глупа шумиха вокруг «умных» часов? Андрей Письменный Опубликовано 30 апреля 2013 В шестнадцатом веке баварскими мастерами был изобретён первый настоящий персональный гаджет в истории человечества — наручные часы. Распространёнными часы


Ионизаторы и озонаторы: насколько они полезны

Из книги автора

Ионизаторы и озонаторы: насколько они полезны Человеческая деятельность, развитие промышленного производства, рост выброса вредных веществ негативно влияют на окружающую среду, изменяя структуру воздуха и приводя к уменьшению количества в нем легких ионов, особенно