Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

// и присваиваем его вновь

Этот стиль предпочтительнее для небольших объектов, таких как переменные типа

int
. Однако передача значений туда и обратно не всегда реальна. Например, можно написать функцию, модифицирующую огромную структуру данных, такую как вектор, содержащий 10 тыс. переменных типа
int
; мы не можем копировать эти 40 тыс. байтов (как минимум, вдвое) с достаточной эффективностью.

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

Использование передачи аргумента с помощью ссылок предостерегает программиста о том, что значение может измениться. Рассмотрим пример.

int x = 7;

incr_p(&x); // здесь необходим оператор &

incr_r(x);

Необходимость использования оператора

&
в вызове функции
incr_p(&x)
обусловлена тем, что пользователь должен знать о том, что переменная
x
может измениться. В противоположность этому вызов функции
incr_r(x)
“выглядит невинно”. Это свидетельствует о небольшом преимуществе передачи указателя.

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

incr_p(0); // крах: функция incr_p пытается разыменовать нуль

int* p = 0;

incr_p(p); // крах: функция incr_p пытается разыменовать нуль

Совершенно очевидно, что это ужасно. Человек, написавший функцию,

incr_p
, может предусмотреть защиту.

void incr_p(int* p)

{

if (p==0) error("Функции incr_p передан нулевой указатель");

++*p; // разыменовываем указатель и увеличиваем на единицу

// объект, на который он установлен

}

Теперь функция

incr_p
выглядит проще и приятнее, чем раньше. В главе 5 было показано, как устранить проблему, связанную с некорректными аргументами. В противоположность этому пользователи, применяющие ссылки (например, в функции
incr_r
), должны предполагать, что ссылка связана с объектом. Если “передача пустоты” (когда объект на самом деле не передается) с точки зрения семантики функции вполне допустима, аргумент следует передавать с помощью указателя. Примечание: это не относится к операции инкрементации — поскольку при условии
p==0
в этом случае следует генерировать исключение.

Итак, правильный ответ формулируется так: выбор зависит от природы функции.

• Для маленьких объектов предпочтительнее передача по значению.

• Для функций, допускающих в качестве своего аргумента “нулевой объект” (представленный значением

0
), следует использовать передачу указателя (и не забывать проверку нуля).

• В противном случае в качестве параметра следует использовать ссылку.

См. также раздел 8.5.6.

17.9.2. Указатели, ссылки и наследование

В разделе 14.3 мы видели, как можно использовать производный класс, такой как

Circle
, вместо объекта его открытого базового класса
Shape
. Эту идею можно выразить в терминах указателей или ссылок: указатель
Circle*
можно неявно преобразовать в указатель
Shape
, поскольку класс
Shape
является открытым базовым классом по отношению к классу
Circle
. Рассмотрим пример.

void rotate(Shape* s, int n); // поворачиваем фигуру *s на угол n

Shape* p = new Circle(Point(100,100),40);

Circle c(Point(200,200),50);

rotate(&c,45);

Это можно сделать и с помощью ссылок.

void rotate(Shape& s, int n); // поворачиваем фигуру *s на угол n

Shape& r = c;

rotate(c,75);

Этот факт является чрезвычайно важным для большинства объектно-ориентированных технологий программирования (см. разделы 14.3, 14.4).

17.9.3. Пример: списки

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

  • Читать дальше
  • 1
  • ...
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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