Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Rvalue ссылки






Разница между lvalue (которые могут использоваться слева от оператора присваивания) и rvalue значениями (которые могут использоваться справа от оператора присваивания) ведут свое начало от Кристофера Страчи (Christopher Strachey) («папы» дальнего родственника С++ под названием CPL и его денотационных семантик). В языке С++ неконстантная ссылка может быть связана с lvalue, константная ссылка – с lvalue или rvalue, но не существует ничего, что может быть связано с неконстантным rvalue значением. Это сделано для защиты от изменения значений временных объектов, которые будут уничтожены до того, как новым значением можно будет воспользоваться. Например:

void incr(int& a) { ++a; }

int i = 0;

incr(i); // i буде равняться 1

incr(0); // ошибка: 0 не является lvalue

 

Если бы вызов incr(0) был бы разрешен, то тогда либо будет увеличено значение временной переменной, которое никто не сможет увидеть, либо, что еще хуже, 0 станет равен 1. Последний вариант звучит глупо, но подобный баг был в ранних версиях компилятора Fortran, который позволял втихую изменить ячейку памяти, хранившую 0.

Пока все хорошо, но давайте рассмотрим следующий пример:

// " старый добрый обмен значениями"

template< class T> swap(T& a, T& b)

{

T tmp(a); // теперь у нас есть две копии a

a = b; // теперь у нас есть две копии b

b = tmp; // теперь у нас есть две копии tmp (aka a)

}

 

Если для типа T копирование элементов является дорогой операцией, как например, для типов string или vector, операция swap также становится достаточно дорогой операцией (поэтому в стандартной библиотеке у нас есть специализированные версии методов swap для строки и вектора). Обратите внимание на интересный момент: мы вообще не хотим делать никаких копий. Мы просто хотим поменять значения a, b и tmp.

Для перемещения, а не копирования аргументов в С++11 мы можем определить «конструкторы перемещения» (move constructors) и «операторы перемещения» (move assignments):

template< class T> class vector {

//...

vector(const vector&); // конструктор копирования

vector(vector& &); // конструктор перемещения

vector& operator=(const vector&); // обычное присваивание

vector& operator=(vector& &); // оператор перемещения

}; // обратите внимание: конструктор и оператор перемещения

// принимают неконстантные & &

// они могут (и обычно делают) изменяют свои аргументы

 

& & означает “rvalue-ссылку”. rvalue-ссылки могут быть связаны только с rvalue (но не с lvalue).

X a;

X f();

X& r1 = a; // связывает r1 с a (lvalue)

X& r2 = f(); // ошибка: f() возвращает rvalue;

X& & rr1 = f(); // ok: связывает rr1 с временным объектом

X& & rr2 = a; // ошибка: a – это lvalue

 

Идея семантики перемещения заключается в том, что вместо создания копии, мы можем просто взять значение из источника и заменить его дешевым значением по умолчанию. Например, для выражения s1=s2 с поддержкой перемещения, символы строки s2 скопированы не будут; вместо этого, строка s1 будет рассматривать символы строки s2, как свои собственные и удалит свои исходные данные (возможно передаст их строке s2, которая вскоре будет удалена).

Откуда мы знаем, что перемещение данных из источника является безопасным? Мы говорим об этом компилятору:

template< class T>

void swap(T& a, T& b) // " идеальный обмен значениями" (почти)

{

T tmp = move(a); // может сделать a недействительным

a = move(b); // может сделать b недействительным

b = move(tmp); // может сделать tmp недействительным

}

 

move(x) означает «вы можете рассматривать x в качестве rvalue». Возможно, было бы лучше, если бы move() назывался rval(), но move() уже используется многие годы. Шаблонная функция move() может быть написана на С++11 (см. " Brief introduction to rvalue references") с помощью rvalue-ссылок.

Rvalue-ссылки могут использоваться для создания идеального механизма перенаправления (forwarding).

В стандартной библиотеке С++11 во все контейнеры добавлены конструкторы и операторы перемещения. Также операции добавления новых элементов, такие как insert() и push_back() содержат версии, принимающие rvalue-ссылки. Конечным результатом является то, что производительность стандартных контейнеров и алгоритмов тихо (без вмешательства пользователя) была улучшена за счет уменьшения необходимости копирования.

См. также:

  • the C++ draft section???
  • N1385 N1690 N1770 N1855 N1952
  • [N2027==06-0097] Howard Hinnant, Bjarne Stroustrup, and Bronek Kozicki: A brief introduction to rvalue references
  • [N1377=02-0035] Howard E. Hinnant, Peter Dimov, and Dave Abrahams: A Proposal to Add Move Semantics Support to the C++ Language (original proposal).
  • [N2118=06-0188] Howard Hinnant: A Proposal to Add an Rvalue Reference to the C++ Language Proposed Wording (Revision 3) (final proposal).

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.