Стенли Липпман - Язык программирования C++. Пятое издание
- Название:Язык программирования C++. Пятое издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2014
- Город:Москва
- ISBN:978-5-8459-1839-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стенли Липпман - Язык программирования C++. Пятое издание краткое содержание
Вы держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под
. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. В соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.
С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать их наилучшие способы применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.
Стенли Б. Липпман Жози Лажойе Барбара Э. Му • Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием
• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования
• Изучите принципы и узнайте почему язык С++11 работает именно так
• Воспользуйтесь множеством перекрестных ссылок, способных помочь вам объединить взаимосвязанные концепции и проникнуть в суть
• Ознакомьтесь с современными методиками обучения и извлеките пользу из упражнений, в которых подчеркиваются ключевые моменты, позволяющие избежать проблем
• Освойте лучшие методики программирования и закрепите на практике изученный материал
Исходный код примеров можно загрузить с веб-страницы книги на сайте издательства по адресу: http://www.williamspublishing.com
Язык программирования C++. Пятое издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Таким образом, этот вызов создает экземпляр шаблона move
, который является точно тем, что необходимо для связи ссылки на r-значение с l-значением.
string&& move(string &t)
Тело этого экземпляра возвращает тип static_cast(t)
. В данном случае типом t
является string&
, который приведение преобразует в тип string&&
.
static_cast
поддерживает приведение l-значения к ссылке на r-значениеОбычно оператор
static_cast
может выполнить только доступные преобразования (см. раздел 16.3). Однако для ссылок на r-значение есть специальное разрешение: даже при том, что нельзя неявно преобразовать l-значение в ссылку на r-значение, используя оператор static_cast
, можно явно привести l-значение к ссылке на r-значение.
Привязка ссылки на r-значение к l-значению создает код, который работает с разрешением ссылке на r-значение заменять l-значение. Иногда, как в случае с функцией reallocate()
класса StrVec
(см. раздел 13.6.1), известно, что замена l-значения безопасна. Разрешая осуществлять это приведение, язык позволяет его использование. Вынуждая использовать приведение, язык пытается предотвратить его случайное использование.
И наконец, хотя такие приведения можно написать непосредственно, намного проще использовать библиотечную функцию move()
. Кроме того, использование функции std::move()
существенно облегчает поиск в коде места, потенциально способного заменить l-значения.
Упражнение 16.46. Объясните, что делает этот цикл из функции StrVec::reallocate()
(раздел 13.5):
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
16.2.7. Перенаправление
Некоторые функции должны перенаправлять другим функциям один или несколько своих аргументов с неизменными типами. В таких случаях необходимо сохранить всю информацию о перенаправленных аргументах, включая то, является ли тип аргумента константой и является ли аргумент l- или r-значением.
В качестве примера напишем функцию, получающую вызываемое выражение и два дополнительных аргумента. Функция вызовет предоставленное вызываемое выражение с другими двумя аргументами в обратном порядке. Вот первый фрагмент функции обращения:
// шаблон, получающий вызываемое выражение и два параметра
// вызывает предоставленное выражение с "обращенными" параметрами
// flip1 - неполная реализация: спецификатор const верхнего уровня и
// ссылки теряются
template
void flip1(F f, T1 t1, T2 t2) {
f(t2, t1);
}
Этот шаблон работает прекрасно, пока он не используется для вызова функции со ссылочным параметром:
void f(int v1, int &v2) // обратите внимание, v2 - ссылка
{
cout << v1 << " " << ++v2 << endl;
}
Здесь функция f()
изменяет значение аргумента, привязанного к параметру v2
. Но если происходит вызов функции f()
через шаблон flip1
, внесенные функцией f()
изменения не затронут первоначальный аргумент:
f(42, i); // f() изменяет свой аргумент i
flip1(f, j, 42); // вызов f() через flip1 оставляет j неизменным
Проблема в том, что j
передается параметру t1
шаблона flip1
. Этот параметр имеет простой, не ссылочный тип int
, а не int&
. Таким образом, этот вызов создает следующий экземпляр шаблона flip1
:
void flip1(void(*fcn)(int, int&), int t1, int t2);
Значение j
копируется в t1
. Ссылочный параметр в функции f()
связан с t1
, а не с j
.

Чтобы передать ссылку через функцию, необходимо переписать ее так, чтобы параметры сохраняли принадлежность своих аргументов к l-значениям. Немного поразмыслив, можно предположить, что константность аргументов также необходимо сохранить.
Всю информацию о типе аргумента можно сохранить, определив соответствующий ему параметр функции как ссылку на r-значение параметра типа шаблона. Использование ссылочного параметра (l- или r-значение) позволяет сохранить константность, поскольку спецификатор const
в ссылочном типе нижнего уровня. Благодаря сворачиванию ссылок (см. раздел 16.2.5), если определить параметры функции как T1&&
и T2&&
, можно сохранить принадлежность к l- или r-значениям аргументов функции (см. раздел 16.2.5):
template
void flip2(F f, T1 &&t1, T2 &&t2) {
f(t2, t1);
}
Как и прежде, если происходит вызов flip2(f, j, 42)
, l-значение j
передается параметру t1
. Однако в функции flip()
для T1
выводится тип int&
, а значит, тип t1
сворачивается в int&
. Ссылка t1
связана с j
. Когда функция flip()
вызывает функцию f()
, ссылочный параметр v2
в функции f()
привязан к t1
, который, в свою очередь, привязан к j
. Когда функция f()
осуществляет инкремент v2
, это изменяет значение j
.
Параметр функции, являющийся ссылкой на r-значение параметра типа шаблона (т.е.
Т&&
), сохраняет константность и принадлежность к l- или r-значениям соответствующих ему аргументов.
Эта версия функции flip()
решает одну половину проблемы. Она работает прекрасно с функциями, получающими ссылки на l-значение, но неприменима для вызова функций с параметрами ссылок на r-значение. Например:
void g(int &&i, int& j) {
cout << i << " " << j << endl;
}
Если попытаться вызывать функцию g()
через функцию flip()
, то для параметра ссылки на r-значение функции g()
будет передан параметр t2
. Даже если функции flip()
было передано r-значение, функции g()
будет передан параметр, носящий в функции flip()
имя t2
:
flip2(g, i, 42); // ошибка: нельзя инициализировать int&& из l-значения
Параметр функции, как и любая другая переменная, является выражением l-значения (см. раздел 13.6.1). В результате вызов функции g()
в функции flip()
передает l-значение параметру ссылки на r-значение функции g()
.

std::forward()
для сохранения информации типа в вызовеЧтобы передать функции
flip()
параметры способом, сохраняющим типы первоначальных аргументов, можно использовать новую библиотечную функцию forward()
. Как и функция move()
, функция forward()
определяется в заголовке utility
. В отличие от функции move()
, функцию forward()
следует вызывать с явным аргументом шаблона (см. раздел 16.2.2). Для этого явного аргумента типа функция forward()
возвращает ссылку на r-значение. Таким образом, типом возвращаемого значения функции forward
будет Т&&
.
Интервал:
Закладка: