Стенли Липпман - Язык программирования C++. Пятое издание
- Название:Язык программирования C++. Пятое издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2014
- Город:Москва
- ISBN:978-5-8459-1839-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стенли Липпман - Язык программирования C++. Пятое издание краткое содержание
Вы держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под
. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. В соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.
С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать их наилучшие способы применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.
Стенли Б. Липпман Жози Лажойе Барбара Э. Му • Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием
• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования
• Изучите принципы и узнайте почему язык С++11 работает именно так
• Воспользуйтесь множеством перекрестных ссылок, способных помочь вам объединить взаимосвязанные концепции и проникнуть в суть
• Ознакомьтесь с современными методиками обучения и извлеките пользу из упражнений, в которых подчеркиваются ключевые моменты, позволяющие избежать проблем
• Освойте лучшие методики программирования и закрепите на практике изученный материал
Исходный код примеров можно загрузить с веб-страницы книги на сайте издательства по адресу: http://www.williamspublishing.com
Язык программирования C++. Пятое издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Параметру функции, являющемуся ссылкой на r-значение на тип параметра шаблона (т.е.
Т&&
), может быть передан аргумент любого типа. Когда такому параметру передается l-значение, экземпляр параметра функции создается как обычная ссылка на l-значение ( T&
).
У того факта, что параметр шаблона может быть выведен как ссылочный тип, имеются удивительные последствия для кода в шаблоне:
template void f3(Т&& val) {
T t = val; // копировать или привязать ссылку?
t = fcn(t); // изменит ли присвоение только t или val и t?
if (val == t) { /* ... */ } // всегда истинно, если Т - ссылочный тип
}
Когда вызов функции f3()
происходит для такого r-значения, как литерал 42
, T
имеет тип int
. В данном случае локальная переменная t
имеет тип int
и инициализируется при копировании значения параметра val
. При присвоении переменной t параметр val
остается неизменным.
С другой стороны, когда происходит вызов функции f3()
для l-значения i
, типом T
будет int&
. Когда определяется и инициализируется локальная переменная t
, у нее будет тип int&
. Инициализация переменной t
свяжет ее с параметром val
. При присвоении переменной t
одновременно изменяется и параметр val
. В этом экземпляре функции f3()
оператор if
всегда будет возвращать значение true
.
На удивление сложно написать правильный код, когда задействованные типы могут быть простыми (не ссылочными) типами или ссылочными типами (хотя такие классы трансформации типов, как remove_reference
(см. раздел 16.2.3), вполне могут помочь в этом).
На практике параметры в виде ссылки на r-значение используются в одном из двух случаев: либо когда шаблон перенаправляет свои аргументы, ли когда шаблон перегружается. Перенаправление рассматривается в разделе 16.2.7, а перегрузка шаблона в разделе 16.3, а пока достаточно знать, что стоит обратить внимание на то, что шаблоны функций, использующие ссылки на r-значение, зачастую используют перегрузку таким же образом, как описано в разделе 13.6.3:
template void f(Т&&); // привязка к не константным
// r-значениям
template void f(const T&); // l-значения и константные
// r-значения
Подобно нешаблонным функциям, первая версия будет связана с изменяемым r-значением, а вторая с l-значением или константным r-значением.
Упражнение 16.42. Определите типы Т
и val
в каждом из следующих вызовов:
template void g(T&& val);
int i = 0; const int ci = i;
(a) g(i); (b) g(ci); (c) g(i * ci);
Упражнение 16.43. Используя определенную в предыдущем упражнении функцию, укажите, каким будет параметр шаблона g()
при вызове g(i = ci)
?
Упражнение 16.44. Используя те же три вызова, что и в первом упражнении, определите типы T
, если параметр функции g()
объявляется как T
(а не Т&&
) и как const Т&
?
Упражнение 16.45. С учетом следующего шаблона объясните происходящее при вызове функции g()
с таким литеральным значением, как 42, и с переменной типа int
?
template void g(T&& val) { vector v; }
16.2.6. Функция
std::move()
Библиотечная функция move()
(см. раздел 13.6.1) — хороший пример шаблона, использующего ссылки на r-значение. К счастью, функцию move()
можно использовать, не понимая механизма работы используемого ею шаблона. Однако изучение работы функции move()
может помочь понять и использовать шаблоны.
В разделе 13.6.2 обращалось внимание на то, что, хотя и нельзя непосредственно привязать ссылку на r-значение к l-значению, функцию move()
можно использовать для получения ссылки на r-значение, связанной с l-значением. Поскольку функция move()
может получать аргументы, по существу, любого типа, нет ничего удивительного в том, что move()
— это шаблон функции.
std::move()
Стандартное определение функции move()
таково:
// об использовании typename в типе возвращаемого значения и
// приведении см. раздел 16.1.3
// remove_reference рассматривается в разделе 16.2.3
template
typename remove_reference::type&& move(T&& t) {
// static_cast рассматривается в разделе 4.11.3
return static_cast::type&&>(t);
}
Этот код короток, но сложен. В первую очередь, параметр функции move()
, Т&&
является ссылкой на r-значение типа параметра шаблона. Благодаря сворачиванию ссылок этот параметр может соответствовать аргументу любого типа. В частности, функции move()
можно передать либо l-, либо r-значение:
string s1("hi!"), s2;
s2 = std::move(string("bye!")); // ok: перемещение r-значения
s2 = std::move(s1); // ok: но после присвоения
// значение s1 неопределенно
std::move()
В первом присвоении аргумент функции move()
является r-значением, полученным в результате выполнения конструктора string("bye")
класса string
. Как уже упоминалось, при передаче r-значения ссылочному r-значению параметра функции выведенный из этого аргумента тип является ссылочным типом (см. раздел 16.2.5). Таким образом, в вызове std::move(string("bye!"))
:
• выведенным типом T
будет string
;
• следовательно, экземпляр шаблона remove_reference
создается с типом string
;
• тип-член type
класса remove_reference
будет иметь тип string
;
• типом возвращаемого значения функции move()
будет string&&
;
• у параметра t
функции move()
будет тип string&&
;
Соответственно, этот вызов создает экземпляр move
, являющийся следующей функцией:
string&& move(string &&t)
Тело этой функции возвращает тип static_cast(t)
. Типом t
уже является string&&
, поэтому приведение не делает ничего. Следовательно, результатом этого вызова будет ссылка на r-значение, которое было дано.
Теперь рассмотрим второе присвоение, которое вызывает функцию std::move(s1)
. В этом вызове аргументом функции move()
является l-значение. Поэтому на сей раз:
• выведенным типом Т
будет string&
(ссылка на тип string
, а не просто string
);
• следовательно, экземпляр шаблона remove_reference
создается с типом string&
;
• тип-член type
класса remove_reference
будет иметь тип string
;
• типом возвращаемого значения функции move()
все еще будет string&&
;
• параметр t
функции move()
будет создан как экземпляр string& &&
, который сворачивается в string&
.
Интервал:
Закладка: