Ссылка на rvalue - это тип, который ведет себя так же, как обычный ссылочный X & amp ;, за несколькими исключениями. Наиболее важным является то, что когда дело доходит до разрешения функции перегрузки, lvalues предпочитают ссылки на lvalue старого стиля, тогда как rvalues предпочитают новые ссылки rvalue:
void foo(X& x); // lvalue reference overload
void foo(X&& x); // rvalue reference overload
X x;
X foobar();
foo(x); // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)
Итак, что такое rvalue? Все, что не является lvalue. Lvalue является выражением, которое относится к ячейке памяти и позволяет нам адресовать адрес этой ячейки памяти через & amp; оператор.
Понятно, во-первых, какие значения выполняются с помощью примера:
class Sample {
int *ptr; // large block of memory
int size;
public:
Sample(int sz=0) : ptr{sz != 0 ? new int[sz] : nullptr}, size{sz}
{}
// copy constructor that takes lvalue
Sample(const Sample& s) : ptr{s.size != 0 ? new int[s.size] :\
nullptr}, size{s.size}
{
std::cout << "copy constructor called on lvalue\n";
}
// move constructor that take rvalue
Sample(Sample&& s)
{ // steal s's resources
ptr = s.ptr;
size = s.size;
s.ptr = nullptr; // destructive write
s.size = 0;
cout << "Move constructor called on rvalue." << std::endl;
}
// normal copy assignment operator taking lvalue
Sample& operator=(const Sample& s)
{
if(this != &s) {
delete [] ptr; // free current pointer
ptr = new int[s.size];
size = s.size;
}
cout << "Copy Assignment called on lvalue." << std::endl;
return *this;
}
// overloaded move assignment operator taking rvalue
Sample& operator=(Sample&& lhs)
{
if(this != &s) {
delete [] ptr; //don't let ptr be orphaned
ptr = lhs.ptr; //but now "steal" lhs, don't clone it.
size = lhs.size;
lhs.ptr = nullptr; // lhs's new "stolen" state
lhs.size = 0;
}
cout << "Move Assignment called on rvalue" << std::endl;
return *this;
}
//...snip
};
Операторы конструктора и присваивания были перегружены версиями, которые принимают ссылки rvalue. Ссылки Rvalue позволяют функции разветвляться во время компиляции (через разрешение перегрузки) при условии «Я вызываюсь на lvalue или rvalue?». Это позволило нам создать более эффективные операторы конструктора и присваивания выше, чем переместить ресурсы, а скорее скопировать их.
Компилятор автоматически разветвляется во время компиляции (в зависимости от того, будет ли он вызываться для lvalue или rvalue), выберите, нужно ли вызывать конструктор перемещения или оператор назначения перемещения.
Подведение итогов: ссылки rvalue позволяют переносить семантику (и совершенную переадресацию, обсуждаемую в ссылке ниже).
Одним из практических понятных примеров является шаблон класса std :: unique_ptr. Поскольку unique_ptr сохраняет исключительную собственность на свой основной необработанный указатель, unique_ptr не может быть скопирован. Это нарушит их инвариант исключительной собственности. Поэтому у них нет конструкторов копирования. Но у них есть конструкторы перемещения:
template class unique_ptr {
//...snip
unique_ptr(unique_ptr&& __u) noexcept; // move constructor
};
std::unique_ptr ptr2{ptr1};// compile error: no copy ctor.
// So we must first cast ptr1 to an rvalue
std::unique_ptr ptr2{std::move(ptr1)};
std::unique_ptr TakeOwnershipAndAlter(std::unique_ptr param,\
int size)
{
for (auto i = 0; i < size; ++i) {
param[i] += 10;
}
return param; // implicitly calls unique_ptr(unique_ptr&&)
}
// Now use function
unique_ptr ptr{new int[10]};
// first cast ptr from lvalue to rvalue
unique_ptr new_owner = TakeOwnershipAndAlter(\
static_cast&&>(ptr), 10);
cout << "output:\n";
for(auto i = 0; i< 10; ++i) {
cout << new_owner[i] << ", ";
}
output:
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
static_cast
обычно делается с помощью std :: move
// first cast ptr from lvalue to rvalue
unique_ptr new_owner = TakeOwnershipAndAlter(std::move(ptr),0);
Отличная статья, объясняющая все это и многое другое (например, как rvalues позволяют совершенную переадресацию, и что это означает) с большим количеством хороших примеров - это ссылки на C ++ Rvalue Томаса Беккера . Этот пост в значительной степени опирался на его статью.
Короче введение Краткое введение в Rvalue Ссылки Stroutrup, et. аль
У меня была похожая проблема. Когда я создавал резюме в Angular, я хотел показать mat-horizontal-stepper
, когда экран больше 700 пикселей, и mat-vertical-stepper
, когда он меньше его. Поэтому я создал событие с HostListener
по window:resize
.
Это мое развернутое резюме, если вы измените размер, вы увидите ожидаемое поведение.
И это файл TS моего компонента, в строке 36 вы можете найти HostListener
.