Він оголошує рецензію на значення (стандартна пропозиція doc).
Ось вступ до рецензуючих посилань .
Ось фантастичний глибокий огляд рецензійних посилань одного із стандартних розробників бібліотеки Microsoft .
ПОПЕРЕДЖЕННЯ: пов'язана стаття про MSDN ("Посилання Rvalue: C ++ 0x Особливості у VC10, частина 2") є дуже чітким вступом до посилань на Rvalue, але робить заяви про посилання на Rvalue, які колись були правдивими у проекті C ++ 11 стандартні, але не відповідають дійсності для остаточного! Зокрема, в різних точках сказано, що посилання на оцінку може пов'язуватися з значеннями, що колись було правдою, але було змінено (наприклад, int x; int && rrx = x; більше не компілюється в GCC) - drewbarbs 13 липня 1414 о 16:12
Найбільша різниця між посиланням на C ++ 03 (тепер його називають посиланням на значення в C ++ 11) полягає в тому, що воно може прив'язуватися до рейтингу, як тимчасове, без необхідності const. Таким чином, цей синтаксис тепер законний:
T&& r = T();
Довідники rvalue насамперед передбачають наступне:
Рухайте семантику . Конструктор переміщення та оператор присвоєння переміщення тепер можуть бути визначені, що приймає посилання rvalue замість звичайної посилання const-lvalue. Переміщення функціонує як копія, за винятком того, що воно не зобов'язане зберігати джерело без змін; насправді воно зазвичай модифікує джерело таким чином, що воно більше не володіє переміщеними ресурсами. Це відмінно підходить для усунення сторонніх копій, особливо в стандартних реалізаціях бібліотеки.
Наприклад, конструктор копій може виглядати так:
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
Якби цей конструктор був переданий тимчасовим, копія була б непотрібною, оскільки ми знаємо, що тимчасова буде просто знищена; чому б не скористатися ресурсами тимчасово виділеними? У C ++ 03 немає ніякого способу запобігти копії, оскільки ми не можемо визначити, що ми були прийняті тимчасово. У C ++ 11 ми можемо перевантажити конструктор переміщення:
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
Зауважте тут велику різницю: конструктор ходу фактично змінює свій аргумент. Це ефективно "перемістить" тимчасове в об'єкт, який будується, тим самим усунувши зайву копію.
Конструктор переміщення буде використовуватися для тимчасових посилань та для неконструктивних посилань на значення, які явно перетворюються на посилання rvalue за допомогою std::move
функції (він просто виконує перетворення). Наступний код викликає конструктор переміщення для f1
та f2
:
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
Ідеальне переадресація . посилання rvalue дозволяє нам належним чином пересилати аргументи для шаблонних функцій. Візьмемо для прикладу цю заводську функцію:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
Якщо ми зателефонували factory<foo>(5)
, буде виведений аргумент int&
, який є , який не буде прив'язуватися до буквального 5, навіть якщо foo
конструктор має а int
. Добре, ми могли б замість цього використати A1 const&
, але що робити, якщо foo
аргумент конструктора приймає за допомогою посилань без контрасту? Щоб зробити справді загальну функцію заводу, нам доведеться перевантажувати завод A1&
і знову A1 const&
. Це може бути добре, якщо фабрика приймає 1 тип параметра, але кожен додатковий тип параметра помножить необхідну перевантаження, встановлену на 2. Це дуже швидко неможливо досягти.
посилання rvalue вирішує цю проблему, дозволяючи стандартній бібліотеці визначити std::forward
функцію, яка може правильно пересилати посилання lvalue / rvalue. Для отримання додаткової інформації про те, як std::forward
працює, дивіться цю відмінну відповідь .
Це дозволяє нам визначити заводську функцію так:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
Тепер значення rvalue / lvalue-аргументу зберігається при передачі T
конструктору s. Це означає, що якщо завод називається за допомогою rvalue, T
конструктор викликається з rvalue. Якщо завод називається за допомогою значення lvalue, T
конструктор викликається рівнем lvalue. Удосконалена функція заводу працює завдяки одному спеціальному правилу:
Коли тип параметру функції має вигляд, у T&&
якому T
параметр шаблону, а аргумент функції є значенням типу A
, тип A&
використовується для виведення аргументу шаблону.
Таким чином, ми можемо використовувати фабрику так:
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
Важливі референтні властивості оцінювання :
- Для роздільної здатності перевантаження lvalues віддають перевагу прив'язці до посилань на lvalue, а rvalues віддають перевагу прив'язці до посилань rvalue . Отже, чому часописи віддають перевагу виклику конструктора переміщення / оператора присвоєння переміщення над конструктором копіювання / оператором призначення.
- посилання rvalue неявно пов'язуватиметься з rvalues та temporaries, які є результатом неявного перетворення . тобто
float f = 0f; int&& i = f;
добре сформований, тому що float неявно перетворюється на int; посилання на тимчасове, що є результатом перетворення.
- Іменовані посилання rvalue - це значення. Неназвані посилання rvalue - це rvalues. Це важливо, щоб зрозуміти, чому
std::move
дзвінок необхідний у:foo&& r = foo(); foo f = std::move(r);