MyTetra Share
Делитесь знаниями!
Rvalue-ссылки в языке C++
Время создания: 14.06.2023 10:33
Автор: Дмитрий Пономарев
Текстовые метки: C++, Си++, ссылка, rvalue, lvalue, &&, двойной, амперсанд
Раздел: Компьютер - Программирование - Язык C++ (Си++) - Стандарт C++11 и выше
Запись: xintrea/mytetra_syncro/master/base/1686728621we8e7xdih3/text.html на raw.github.com

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

Для примеров будем использовать класс:


class Int

{

    int m_Value;

public:

    Int(int val) : m_Value(val) {}

    int Get() const { return m_Value; }

    void Set(int val) { m_Value = val; }

};


Как и обычные ссылки, rvalue-ссылки необходимо инициализировать.


Int&& r0; // error C2530: 'r0' : references must be initialized


Первым отличием rvalue-ссылок от обычных С++ ссылок заключается в том, что их нельзя инициализировать с помощью lvalue. Пример:


Int i(7);

Int&& r1 = i; // error C2440: 'initializing' : cannot convert from 'Int' to 'Int &&'


Для корректной инициализации необходимо использовать rvalue:


Int&& r2 = Int(42); // OK

Int&& r3 = 5;       // OK


или lvalue должно быть явно приведено к типу rvalue-ссылки:


Int&& r4 = static_cast<Int&&>(i); // OK


Вместо оператора приведения к типу rvalue-ссылки обычно используется функция (точнее шаблон функции) std::move(), делающая то же самое (заголовочный файл <utility>).

Rvalue ссылки можно инициализировать с помощью rvalue встроенного типа, для обычных ссылок это запрещено.


int&& r5 = 2 * 2; // OK

int& r6 = 2 * 2;  // error


После инициализации rvalue-ссылки можно использовать как обычные ссылки.


Int&& r = 7;

std::cout << r.Get() << '\n'; // Вывод: 7

r.Set(19);

std::cout << r.Get() << '\n'; // Вывод: 19


Rvalue-ссылки неявно приводятся к обычным ссылкам.


Int&& r = 5;

Int& x = r;           // OK

const Int& cx = r;    // OK


Rvalue-ссылки редко используются как самостоятельные переменные, обычно они используются как параметры функций. В соответствии с правилами инициализации, если функция имеет параметры типа rvalue-ссылок, то ее можно вызвать только для rvalue аргументов.


void Foo(Int&&);


Int i(7);

Foo(i);            // error, lvalue аргумент

Foo(std::move(i)); // OK

Foo(Int(4));       // OK

Foo(5);            // OK


Если имеются несколько перегруженных функций, то при разрешении перегрузки для rvalue аргумента версия с параметром типа rvalue-ссылка имеет приоритет над версией с параметром типа обычная ссылка или обычная ссылка на константу, хотя последние и могут быть допустимыми вариантами. И это правило является второй ключевой особенностью rvalue-ссылок.

Функция с параметром, передаваемым по значению, и перегруженная версия, имеющая параметр типа rvalue-ссылка, будут неразрешимы (ambiguous) для rvalue аргументов.

Для примера рассмотрим перегруженные функции


void Foo(Int&&);

void Foo(const Int&);


и несколько вариантов их вызова


Int i(7);

Foo(i);            // Foo(const Int&)

Foo(std::move(i)); // Foo(Int&&)

Foo(Int(6));       // Foo(Int&&)

Foo(9);            // Foo(Int&&)


Следует обратить внимание на один важный момент: именованная rvalue-ссылка сама по себе является lvalue.


Int&& r = 7;

Foo(r);            // Foo(const Int&)

Foo(std::move(r)); // Foo(Int&&)


Это надо учитывать при определении функций, имеющих параметры типа rvalue-ссылка, такие параметры являются lvalue и могут потребовать использования std::move(). См. пример перемещающего конструктора и оператора перемещающего присваивания в разделе 2.4.

Еще одно нововведение С++11, связанное с rvalue-ссылками — это ссылочные квалификаторы для нестатических функций-членов. Они позволяют перегружать по типу (lvalue/rvalue) скрытого параметра this.


class X

{

public:

    X();

    void DoIt() &;  // this указывает на lvalue

    void DoIt() &&; // this указывает на rvalue

// ...

};


X x;

x.DoIt();   // DoIt() &

X().DoIt(); // DoIt() &&


Так же в этом разделе:
 
MyTetra Share v.0.60
Яндекс индекс цитирования