Правила программирования на Си и Си++



         

121. Никогда не используйте ссылки в качестве результатов, пользуйтесь указателями - часть 2


Вчера вы написали следующий код:

f( const char

*p )

{

   char *p = new char[1024];

   load( p );

   char word[64];

   copy_word( word, p );

   delete( p ); // Сюрприз!

p был модифицирован, поэтому весь

}               // этот участок памяти обращается в кучу мусора!

Главная проблема состоит в том, что, глядя на вызов copy_word( word, p ), вы не получаете подсказки о возможном изменении p в подпрограмме. Чтобы добраться до этой информации, вы должны взглянуть на прототип этой функции (который, вероятно, скрыт на 6-ом уровне вложенности в заголовочном файле). Огромные проблемы при сопровождении.

Если что-то похоже на обычный вызов функции Си, то оно должно и действовать как вызов обычной функции Си. Если бы автор copy_word()

использовал указатель для второго аргумента, то вызов выглядел бы подобным образом:

copy_word( word, &p );

Этот дополнительный знак &

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

Это не значит, что вы должны избегать ссылок. Четвертая причина в начале этого раздела вполне законна: ссылки являются замечательным способом избегать ненужных затрат на копирование, неявных при передаче по значению. Тем не менее, для обеспечения безопасности ссылочные аргументы должны всегда ссылаться на константные объекты. Для данного прототипа:

f( const some_class &obj );

этот код вполне законен:

some_class an_object;

f( an_object );

Он похож на вызов по значению и при этом, что более важно, действует подобно вызову по значению —

модификатор const

предотвращает модификацию an_object в функции f(). Вы получили эффективность вызова по ссылке без его проблем.

Подведем итог: Я решаю, нужно или нет использовать ссылку, вначале игнорируя факт существования ссылок. Входные аргументы функций передаются по значению, а выходные —




Содержание  Назад  Вперед