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

на главную - закладки

Жанры

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Майерс Скотт

Шрифт:

// зашифрованного пароля в переменную 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.

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

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

Правило 27: Не злоупотребляйте приведением типов

Правила C++ разработаны так, чтобы неправильно работать с типами было невозможно. Теоретически, если ваша программа компилируется без ошибок, значит, она не пытается выполнить никаких небезопасных или бессмысленных операций с объектами. Это ценная гарантия. Не надо от нее отказываться.

Поделиться:
Популярные книги

Возвышение Меркурия. Книга 2

Кронос Александр
2. Меркурий
Фантастика:
фэнтези
5.00
рейтинг книги
Возвышение Меркурия. Книга 2

Безымянный раб

Зыков Виталий Валерьевич
1. Дорога домой
Фантастика:
фэнтези
9.31
рейтинг книги
Безымянный раб

Волк 4: Лихие 90-е

Киров Никита
4. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 4: Лихие 90-е

Кремлевские звезды

Ромов Дмитрий
6. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Кремлевские звезды

Газлайтер. Том 4

Володин Григорий
4. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 4

Восход. Солнцев. Книга VIII

Скабер Артемий
8. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга VIII

Кровь и Пламя

Михайлов Дем Алексеевич
7. Изгой
Фантастика:
фэнтези
8.95
рейтинг книги
Кровь и Пламя

Объединитель

Астахов Евгений Евгеньевич
8. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Объединитель

Комбинация

Ланцов Михаил Алексеевич
2. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Комбинация

На границе империй. Том 7. Часть 2

INDIGO
8. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
6.13
рейтинг книги
На границе империй. Том 7. Часть 2

Дайте поспать!

Матисов Павел
1. Вечный Сон
Фантастика:
юмористическое фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Дайте поспать!

Бальмануг. Студентка

Лашина Полина
2. Мир Десяти
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бальмануг. Студентка

Довлатов. Сонный лекарь

Голд Джон
1. Не вывожу
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Довлатов. Сонный лекарь

Мастер Разума VII

Кронос Александр
7. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума VII