TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #394 4.34K
​​const rvalue reference
#опытным

В прошлом посте мельком упомянул эту конструкцию, а в этом решил раскрыть по-подробнее.

Правые ссылки были введены в С++11 и с тех пор помогают в реализации семантики перемещения. С помощью таких ссылок мы можем убрать ненужное глубокое копирование объектов и внедрить "перемещение" одного объекта в другой. Достигается это с помощью специальных методов: конструктора перемещения и перемещающего оператора присваивания. Выглядит это так:

struct Movable {
Movable(int i) : num{new int(i)} {}
Movable(Movable&& other) {
num = other.num;
other.num = nullptr;
std::cout << "Don't have to copy in ctor\n";
}
Movable& operator=(Movable&& other) {
if (this != &other) {
delete num;
num = other.num;
other.num = nullptr;
std::cout << "Don't have to copy in assignment\n";
}
return *this;
}
~Movable() { delete num;}
int * num = nullptr;
}

Movable obj1{5};
Movable obj2{7};
Movable&& rvalue_ref = std::move(obj1);
Movable obj3{std::move(rvalue_ref)};
obj2 = std::move(obj3);

// OUTPUT
// Don't have to copy in ctor
// Don't have to copy in assignment


Эти два специальных метода всегда имеют такую сигнатуру. Даже если их генерирует за нас компилятор.

То есть по идее, правые ссылки нужны, чтобы перенести из значение текущего объекта в новый объект. И для этого первоначальный объект нужно изменить.

Так за каким хреном нам тогда нужны константный правые ссылки? Чтобы что? С первого взгляда это выглядит так: мы принимаем правые все правые ссылки в перегрузку(неконстантные ссылки биндятся к константным), но все равно копируем объект, потому что ничего другого сделать не можем. Звучит, как бред.

Но все же есть применение у этой конструкции.

Дело в том, что T&& могут кастится к const T&, T&& и const T&&. Наиболее подходящей перегрузкой будет T&&, дальше const T&& и, наконец, const T&. А вот левые ссылки к правым вообще не могут преобразовываться.

Соотвественно, если мы хотим принимать только lvalue в функцию и никак не пропускать правые ссылки, то "Хьюстон, у нас проблема!". Если мы просто определим перегрузку для const T&, то rvalue reference все равно смогут попадать в эту перегрузку. Что нас сильно огорчает.

Однако мы можем совершить ход конем: пометить перегрузку const T&& удаленной. Так как удаленные функции все еще участвуют в разрешении перегрузок, то для T&& более подходящим выбором будет const T&&, нежели const T&. Но мы намеренно удаляем эту перегрузку и тогда компилятор выдает ошибку из-за того, что не может найти подходящий вариант функции.

struct T{};

void f(T&) { std::cout << "lvalue ref\n"; }
void f(const T&) { std::cout << "const lvalue ref\n"; }
void f(const T&&) = delete; //{ std::cout << "const rvalue ref\n"; }

const T g() {
return T{};
}

int main() {
f(g()); // error: use of deleted function 'void f(const T&&)'
f(T{}); // error: use of deleted function 'void f(const T&&)'
}


Это применение и еще парочку других мы рассмотрим на реальных примерах в следующий раз.

Remove obstructing things from your life. Stay cool.

#cppcore #cpp11
  • 👍 21
  • 🔥 7
  • ❤ 6
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →