Типичная причина введения ссылок на Rvalue в C ++ заключается в устранить (оптимизировать) лишнее копирование во время оценки сложных выражений C ++.
Тем не менее, есть два методы оптимизации компилятора для C ++ 98 / C ++ 03, которые в основном служат той же цели, а именно
Существует ли какой-либо реальный случай использования, когда вышеуказанные методы (с соответствующим образом написанным кодом) не могут устранить лишнее копирование, но ссылки на значения могут быть успешными?
Ссылки на rvalue разработаны с двумя целями:
В общем, одна из целей семантики перемещения — это оптимизация копирования. Там, где вы можете копировать, вы можете просто перемещать ресурсы, удерживаемые объектом.
std::string str("The quick brown fox jumps over the lazy dog.");
std::cout << str; // Do something
func(std::move(str)); // You do not need str in the subsequent lines, and so move
Кроме того, компилятор может оптимизировать возвращаемое значение функции, где RVO может не применяться
std::vector<std::string> read_lines_from_file(const std::string& filename);
auto lines = read_lines_from_file("file1.txt"); // Can possibly be optimized with RVO
// Do something with lines
lines = read_lines_from_file("file2.txt"); // RVO isn't applicable, but move is
// Do something with lines
Если вы реализуете семантику перемещения в своих классах, скорее всего, вы будете испытывать значительное повышение производительности, когда будете помещать их в контейнеры. Рассматривать std::vector
, Всякий раз, когда вы изменяете элементы std::vector
Через некоторое время произойдет некоторое перераспределение и смещение элементов. В C ++ 98 элементы в основном копируются[1], что является ненужным, так как логически существует только одно представление объекта, которое необходимо в один момент времени. С семантикой перемещения, контейнеры типа std::vector
можно просто перемещать объекты, устраняя лишние копии и, следовательно, повышать производительность вашей программы.
Одним из очень важных применений семантики перемещения является не только оптимизация, но и реализация уникальной семантики владения. Один очень хороший пример std::unique_ptr
в котором его можно перемещать только (его нельзя копировать), поэтому вам гарантировано (при правильном использовании), что есть только один std::unique_ptr
который управляет указателем или ресурсом.
Идеальная пересылка использует rvalue-ссылки и специальные правила вывода шаблонов, чтобы мы могли реализовать идеальные функции пересылки, то есть функции, которые могут пересылать аргументы правильно и без создания копий.
Примеры std::make_shared
и предстоящий std::make_unique
, Также новые emplace*
методы контейнеров, тот, который вы найдете очень полезным и удобным (не говоря уже о том, что он также будет очень эффективным).
Этот ответ обеспечивает очень хорошее и полное объяснение ссылок на rvalue в отношении семантики перемещения и идеальной пересылки.
[1] Одна вещь, которую я услышал из одного из выступлений Бьярна Страуструпа[источник нужен] в том, что контейнеры обычно реализуют некоторую специальную семантику перемещения. Поэтому, как он сказал, вы можете не испытывать такого ускорения.
Если вам нужен один единственный аргумент, почему ссылки на rvalue важны, это unique_ptr
, Это архетип ресурсов управления классами SBRM. Ресурсы по определению не копируются, но менеджеры должны движимое
Собственный контейнер разнородных связанных объектов прост для реализации в качестве контейнера unique_ptr
с базового класса, и это очень распространенная идиома программирования. До ссылок на rvalue никогда не было вполне возможно реализовать это чисто на «родном C ++», и всегда требовалось ручное обслуживание.
Потоки и блокировки являются дополнительными примерами ресурсов.
Короче говоря, оптимизация — это только одна часть истории, но подвижность — это само по себе качество, с которым просто было нелегко справиться, прежде чем ссылаться на rvalue.
Есть две причины для использования ссылок на rvalue и перемещения
семантика.
Для большинства программистов самый важный (или даже единственный
причина, которая влияет на их код) является возможность
поддержка «ограниченная копия». (Извините, я не знаю хорошего имени
для этого.) Как классы iostream, например: вы не
хотите поддержать копирование как таковое, но вы хотите разрешить
строительство в отдельной функции. Типичным примером может быть
поток журнала: вы хотите вернуть соответствующий поток журнала из
функция, но вы хотите только один экземпляр, чей
деструктор будет гарантировать, что действия регистрации (то есть отправка
электронная почта, размещение в системном журнале и т. д.) являются атомарными.
Иногда его также можно использовать для оптимизации; Вы упоминаете
такие вещи, как оптимизация возвращаемого значения и копирование, но они
не всегда применяется, особенно с заданием. Как правило, в
В таких случаях вы игнорируете ссылки и перемещаетесь до
профилировщик сказал, что есть проблема, но если вы
реализуя библиотеку, у вас может не быть такой роскоши.