Я изучил некоторые из новых функций C ++ 11, и одна из них я заметил, это двойной амперсанд при объявлении переменных, например T&& var
.
Для начала, как зовут этого зверя? Я бы хотел, чтобы Google позволил нам искать такие знаки препинания, как этот.
Что именно это значит?
На первый взгляд, это, кажется, двойная ссылка (как двойные указатели в стиле C T** var
), но мне трудно придумать вариант использования для этого.
c++
c++11
rvalue-reference
c++-faq
perfect-forwarding
paxdiablo
источник
источник
:)
Ответы:
Он объявляет ссылку на rvalue (стандартное предложение doc).
Вот введение в rvalue ссылки .
Вот фантастический взгляд в глубину на RValue ссылок по одной из стандартных библиотек Microsoft, разработчиков .
Самым большим отличием ссылки C ++ 03 (теперь называемой ссылкой lvalue в C ++ 11) является то, что она может связываться с rvalue как временная, не будучи константой. Таким образом, этот синтаксис теперь допустим:
rvalue ссылки в первую очередь предусматривают следующее:
Переместить семантику . Теперь можно определить конструктор перемещения и оператор присваивания перемещения, который принимает ссылку rvalue вместо обычной ссылки const-lvalue. Перемещение функционирует как копия, за исключением того, что оно не обязано сохранять источник без изменений; фактически, он обычно изменяет источник так, что он больше не владеет перемещенными ресурсами. Это отлично подходит для устранения посторонних копий, особенно в стандартных реализациях библиотеки.
Например, конструктор копирования может выглядеть так:
Если этот конструктор был передан временный, копия будет ненужной, потому что мы знаем, что временный будет просто уничтожен; почему бы не использовать ресурсы, временно выделенные? В C ++ 03 нет способа предотвратить копирование, так как мы не можем определить, были ли мы переданы временно. В C ++ 11 мы можем перегрузить конструктор перемещения:
Обратите внимание на большую разницу: конструктор перемещения фактически изменяет свой аргумент. Это эффективно «переместит» временный объект в создаваемый объект, тем самым устраняя ненужную копию.
Конструктор перемещения будет использоваться для временных значений и для неконстантных lvalue-ссылок, которые явно преобразуются в rvalue-ссылки с использованием
std::move
функции (он просто выполняет преобразование). Следующий код вызывает конструктор перемещения дляf1
иf2
:Идеальная пересылка . rvalue ссылки позволяют нам правильно пересылать аргументы для шаблонных функций. Возьмем, к примеру, эту заводскую функцию:
Если мы вызвали
factory<foo>(5)
, аргумент будет выведен какint&
, который не будет привязан к литералу 5, даже еслиfoo
конструктор принимаетint
. Что ж, мы могли бы вместо этого использоватьA1 const&
, но что еслиfoo
принять аргумент конструктора по неконстантной ссылке? Для того, чтобы действительно обобщенная функция фабрики, мы должны перегрузить завод поA1&
иA1 const&
. Это может быть хорошо, если фабрика принимает 1 тип параметра, но каждый дополнительный тип параметра умножает необходимую перегрузку, установленную на 2. Это очень быстро не поддерживается.Ссылки на rvalue решают эту проблему, позволяя стандартной библиотеке определять
std::forward
функцию, которая может правильно пересылать ссылки на lvalue / rvalue. Для получения дополнительной информации о томstd::forward
, как работает, посмотрите этот отличный ответ .Это позволяет нам определить фабричную функцию следующим образом:
Теперь аргумент rvalue / lvalue-ness сохраняется при передаче в
T
конструктор. Это означает, что если фабрика вызывается с помощью rvalue, тоT
конструктор вызывается с помощью rvalue. Если factory вызывается с lvalue, тоT
конструктор вызывается с lvalue. Улучшенная фабричная функция работает благодаря одному специальному правилу:Таким образом, мы можем использовать фабрику так:
Важные справочные свойства :
float f = 0f; int&& i = f;
хорошо сформирован, потому что float неявно конвертируется в int; ссылка была бы на временную, которая является результатом преобразования.std::move
вызов необходим в:foo&& r = foo(); foo f = std::move(r);
источник
Named rvalue references are lvalues. Unnamed rvalue references are rvalues.
; не зная этого, я изо всех сил пытался понять, почему людиT &&t; std::move(t);
долгое время занимаются движением, и тому подобное.int x; int &&rrx = x;
больше не компилируется в GCC)typename identity<T>::type& a
эквивалентноT&
?Это обозначает rvalue ссылку. Ссылки Rvalue будут привязываться только к временным объектам, если явно не сгенерировано иначе. Они используются для того, чтобы сделать объекты намного более эффективными при определенных обстоятельствах, а также для предоставления средства, известного как совершенная пересылка, что значительно упрощает код шаблона.
В C ++ 03 вы не можете различить копию неизменяемого lvalue и rvalue.
В C ++ 0x это не так.
Рассмотрим реализацию этих конструкторов. В первом случае строка должна выполнить копирование, чтобы сохранить семантику значения, что предполагает новое выделение кучи. Однако во втором случае мы заранее знаем, что объект, который был передан нашему конструктору, должен немедленно уничтожиться, и он не должен оставаться нетронутым. В этом сценарии мы можем эффективно просто поменять местами внутренние указатели и вообще не выполнять никакого копирования, что существенно более эффективно. Семантика перемещения полезна для любого класса, который имеет дорогостоящее или запрещенное копирование внутренних ссылок на ресурсы. Рассмотрим случай
std::unique_ptr
- теперь, когда наш класс может различать временные и невременные, мы можем заставить семантику перемещения работать правильно, так чтоunique_ptr
не может быть скопировано, но может быть перемещено, что означает, чтоstd::unique_ptr
могут быть законно сохранены в стандартных контейнерах, отсортированы и т. д., тогда как C ++ 03 неstd::auto_ptr
может.Теперь мы рассмотрим другое использование ссылок на rvalue - идеальная пересылка. Рассмотрим вопрос привязки ссылки к ссылке.
Не могу вспомнить, что C ++ 03 говорит по этому поводу, но в C ++ 0x результирующий тип при работе со ссылками на rvalue является критическим. Ссылка rvalue на тип T, где T является ссылочным типом, становится ссылкой типа T.
Рассмотрим простейшую шаблонную функцию - min и max. В C ++ 03 вы должны перегрузить все четыре комбинации const и non-const вручную. В C ++ 0x это всего лишь одна перегрузка. В сочетании с различными шаблонами, это обеспечивает идеальную пересылку.
Я прекратил вычитание возвращаемого типа, потому что не могу вспомнить, как это делается не по назначению, но этот min может принимать любую комбинацию lvalues, rvalues, const lvalues.
источник
std::forward<A>(aref) < std::forward<B>(bref)
? и я не думаю , что это определение будет правильным , если вы попробуете впередint&
иfloat&
. Лучше оставить один тип шаблона формы.Термин «
T&&
когда используется с выводом типа» (например, для идеальной пересылки) в разговорной речи известен как ссылка на пересылку . Термин «универсальная ссылка» был придуман Скоттом Мейерсом в этой статье , но позже был изменен.Это потому, что это может быть либо значение r, либо значение l.
Примеры:
Дополнительную информацию можно найти в ответе на: Синтаксис для универсальных ссылок
источник
Ссылка rvalue - это тип, который ведет себя так же, как обычная ссылка X &, с несколькими исключениями. Наиболее важным является то, что когда речь идет о разрешении перегрузки функций, lvalue предпочитает ссылки lvalue старого стиля, тогда как rvalues предпочитает новые ссылки rvalue:
Так что же такое значение? Все, что не является lvalue. Lvalue - это выражение, которое относится к ячейке памяти и позволяет нам получить адрес этой ячейки памяти через оператор &.
Сначала легче понять, чего достигают значения на примере:
Конструктор и операторы присваивания были перегружены версиями, которые принимают rvalue ссылки. Ссылки на Rvalue позволяют функции разветвляться во время компиляции (с помощью разрешения перегрузки) при условии «Меня вызывают по lvalue или по rvalue?». Это позволило нам создать более эффективные операторы конструктора и присваивания выше, которые перемещают ресурсы, а не копируют их.
Компилятор автоматически выполняет ветвление во время компиляции (в зависимости от того, вызывается ли он для lvalue или rvalue), выбирая, должен ли быть вызван конструктор перемещения или оператор присваивания перемещения.
Подводя итог: ссылки на rvalue допускают семантику перемещения (и идеальную пересылку, обсуждаемую в статье ниже).
Одним из практических простых для понимания примеров является шаблон класса std :: unique_ptr . Так как unique_ptr поддерживает исключительное владение своим базовым необработанным указателем, unique_ptr не может быть скопирован. Это нарушило бы их инвариант исключительной собственности. Поэтому у них нет конструкторов копирования. Но у них есть конструкторы перемещения:
static_cast<unique_ptr<int[]>&&>(ptr)
обычно делается с использованием std :: moveОтличная статья, объясняющая все это и многое другое (например, как значения rvalue позволяют совершенную пересылку и что это значит) с множеством хороших примеров, - объяснение ссылок на C ++ Rvalue Томаса Беккера . Этот пост в значительной степени опирался на его статью.
Более короткое введение - Краткое введение в Rvalue References от Stroutrup, et. аль
источник
Sample(const Sample& s)
должен также копировать содержимое? Тот же вопрос для «оператора присваивания копии».