CHAP8_2 (1018809)

Файл №1018809 CHAP8_2 (Сборник литературы - С и С++)CHAP8_2 (1018809)2017-07-08СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла

Глава 8.В(C). Ссылки

120. Ссылочные аргументы всегда должны быть константами.

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

Использование ссылочных аргументов в языке программирования вызвано четырьмя причинами:

  • Они нужны вам для определения конструктора копии.

  • Они нужны вам для определения перегруженных операций. Если вы определили:

    some_class *operator+( some_class *left, some_class *right );

    то вы должны сделать такое дополнение:

    some_class x, y;

    x = *(&x + &y)

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

    x = x + 1;

  • Вы часто хотите передать объекты по значению, исходя из логики. Например, вы обычно в функцию передаете тип double, а не указатель на double. Тем не менее, тип double представляет собой 8-байтовую упакованную структуру с тремя полями: знаковым битом, мантиссой и порядком. Передавайте в этой ситуации ссылку на константный объект.

  • Если объект какого-нибудь определенного пользователем класса обычно передается по значению, то используйте вместо этого ссылку на константный объект, чтобы избежать неявного вызова конструктора копии.

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

Проблема ссылочных аргументов - сопровождение. В прошлом году один из наших сотрудников написал следующую подпрограмму:

void copy_word( char *target, char *&src ) // src является ссылкой на char*

{

while( isspace(*src) )

++src; // Инкрементировать указатель,

// на который ссылается src.

while( *src && !isspace(*src) )

*target++ = *src++; // Передвинуть указатель,

// на который ссылается src,

// за текущее слово.

}

Автор полагал, что вы будете вызывать copy_word() многократно. Каждый раз подпрограмма копировала бы следующее слово в буфер target и продвигала бы указатель в источнике.

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

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(). Вы получили эффективность вызова по ссылке без его проблем.

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

  • являются объектами какого-то класса (в отличие от основных типов, подобных int);

  • не модифицируются где-то внутри функции.

Объекты, которые передаются по значению и затем модифицируются внутри функции, конечно должны по-прежнему передаваться по значению.

В заключение этого обсуждения рассмотрим пример из реальной жизни того, как не надо использовать ссылки. Объект CDocument содержит список объектов CView. Вы можете получить доступ к элементам этого списка следующим образом:

CDocument *doc;

CView *view;

POSITION pos = doc->GetFirstViewPosition();

while( view = GetNextView(pos) )

view->Invalidate();

Здесь есть две проблемы. Во-первых, у функции GetNextView() неудачное имя. Она должна быть названа GetCurrentViewAndAdvancePosition(), потому что она на самом деле возвращает текущий элемент и затем продвигает указатель положения (который является ссылочным аргументом результата) на следующий элемент. Что приводит нас к второй проблеме: средний читатель смотрит на предыдущий код и задумывается над тем, как завершается этот цикл. Другими словами, здесь скрывается сюрприз. Операция итерации цикла скрыта в GetNextView(pos), поэтому неясно, где она происходит. Ситуация могла быть хуже, если бы цикл был больше и содержал бы несколько функций, использующих pos в качестве аргумента - вы бы не имели никакого представления о том, какая из них вызывает перемещение.

Есть множество лучших способов решения этой проблемы. Простейший заключается в использовании в качестве аргумента GetNextView() указателя вместо ссылки:

POSITION pos = doc->GetFirstViewPosition();

while( p = GetNextView( &pos ) )

view->Invalidate();

Таким способом &pos сообщает вам, что pos будет модифицироваться; иначе зачем передавать указатель? Тем не менее, существуют и лучшие решения. Вот первое:

for( CView *p = doc->GetFirstView(); p ; p = p->NextView() )

p->Invalidate();

Вот второе:

POSITION pos = doc->GetFirstViewPosition();

for( ; pos ; pos = doc->GetNextView(pos) )

(pos->current())->Invalidate();

Вот третье:

CPosition pos = doc->GetFirstViewPosition();

for( ; pos; pos.Advance() )

( pos->CurrentView() )->Invalidate();

Вот четвертый:

ViewListIterator cur_view = doc->View_list(); // Просмотреть весь

// список отображений

// этого документа.

for( ; cur_view ; ++cur_view ) // ++ переходит к следующему отображению.

cur_view->Invalidate(); // -> возвращает указатель View*.

Вероятно, есть еще дюжина других возможностей. Все предыдущее варианты обладают требуемым свойством - в них нет скрытых операций и ясно, как происходит переход к "текущему положению".

122. Не возвращайте ссылки (или указатели) на локальные переменные.

Эта проблема проявляется и в С, где вы не можете вернуть указатель на локальную переменную. Не возвращайте ссылку на объект, который не существует после этого возврата. Следующий код не работает:

some_class &f()

{

some_class x;

// ...

return x;

}

Действительной проблемой здесь является синтаксис С++. Оператор return может располагаться на отдалении от определения возвращаемой величины. Единственный способ узнать, что на самом деле делает return x, - это взглянуть на заголовок функции и посмотреть, возвращает она ссылку,или нет.

123. Не возвращайте ссылки на память, выделенную оператором new.

Каждый вызов new должен сопровождаться delete - подобно malloc() и free(). Я иногда видел людей, старающихся избежать накладных расходов от конструкторам копии перегруженной бинарной операции подобным образом:

const some_class &some_class::operator+( const some_class &r ) const

{

some_class *p = new some_class;

// ...

return *p;

}

Этот код не работает, потому что вы не можете вернуться к этой памяти, чтобы освободить ее. Когда вы пишите:

some_class a, b, c;

c = a + b;

то a + b возвращает объект, а не указатель. Единственным способом получить указатель, который вы можете передать в оператор delete, является:

some_class *p;

c = *(p = &(a + b));

Это даже страшно выговорить. Функция operator+() не может прямо возвратить указатель. Если она выглядит подобным образом:

const some_class *some_class::operator+( const some_class &r ) const

{

some_class *p = new some_class;

// ...

return p;

}

то вы должны записать:

c = *(p = a + b);

что не так страшно, как в предыдущем примере, но все еще довольно плохо. Единственное решение этой задачи состоит в том, чтобы стиснуть зубы и вернуть объект:

const some_class *some_class::operator+( const some_class &r ) const

{

some_class obj;

// ...

return obj;

}

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

Глава 8.Г(D). Конструкторы, деструкторы и operator=( )

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

Генерируемый компилятором конструктор копии (чьим аргументом является ссылка на текущий класс) нужен еще по двум причинам, кроме таблицы виртуальных функций. Во-первых, код на С++, который выглядит как на С, должен и работать, как С. Так как правила копирования, которые относятся к классу, относятся также и к структуре, поэтому компилятор будет вынужден обычно генерировать конструктор копии в структуре, чтобы обрабатывать копирование структур в стиле С. Этот конструктор копии используется явно подобным образом:

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

some_class y = x; // конструктор копии

но кроме этого он используется и неявно в двух ситуациях. Первой является вызов по значению:

some_class x;

f( some_class x ); // передается по значению, а не по ссылке.

// ... // вызывается конструктор копии для передачи x

f( x ); // по значению. Оно должно скопироваться в стек.

Второй является возврат по значению:

g() // Помните, что x - локальная, автоматическая переменная.

{ // Она исчезает после возвращения функцией значения.

some_class x; // Оператор return после этого должен скопировать x куда-нибудь

return x; // в надежное место (обычно в стек после аргументов).

} // Он использует для этой цели конструктор копии.

Генерируемая компилятором функция-операция operator=() нужна лишь для поддержки копирования структур в стиле С там, где не определена операция присваивания.

124. Операция operator=( ) должна возвращать ссылку на константу.

125. Присваивание самому себе должно работать.

Определение operator=( ) должно всегда иметь следующую форму:

class class_name

{

const class_name &operator=( const class_name &r );

};

const class_name &class_name::operator=( const class_name &r )

{

if( this != &r )

{

// здесь скопировать

}

return *this;

}

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

Эта функция возвращает ссылку, потому что она может это сделать. То есть вы могли бы удалить & из объявления возвращаемой величины, и все бы работало прекрасно, но вы бы получили ненужный вызов конструктора копии, вынужденный возвратом по значению. Так как у нас уже есть объект, инициализированный по типу правой части (*this), то мы просто можем его вернуть. Даже если возврат объекта вместо ссылки в действительности является ошибкой для функции operator=(), компилятор просто выполнит то, что вы ему приказали. Здесь не будет сообщения об ошибке; и на самом деле все будет работать. Код просто будет выполняться более медленно, чем нужно.

Наконец, operator=() должен возвращать ссылку на константу просто потому, что не хотите, чтобы кто-нибудь имел возможность модифицировать возвращенный объект после того, как произошло присваивание. Следующее будет недопустимым в случае возврата ссылки на константу:

Характеристики

Тип файла
Документ
Размер
79 Kb
Тип материала
Высшее учебное заведение

Тип файла документ

Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.

Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.

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

Список файлов книги

С и С++ - сборник литературы
C++ Бархатный путь - Марченко А
cpp_001.shtml
cpp_002.shtml
cpp_003.shtml
cpp_004.shtml
cpp_005.shtml
cpp_006.shtml
cpp_007.shtml
cpp_008.shtml
cpp_009.shtml
cpp_010.shtml
cpp_011.shtml
cpp_012.shtml
cpp_013.shtml
cpp_014.shtml
cpp_015.shtml
cpp_016.shtml
cpp_017.shtml
cpp_018.shtml
cpp_019.shtml
cpp_020.shtml
cpp_021.shtml
cpp_022.shtml
cpp_023.shtml
cpp_024.shtml
cpp_025.shtml
cpp_026.shtml
cpp_027.shtml
cpp_030.shtml
cpp_034.shtml
Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7028
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее