В очередной раз убедился, что мое понимание ссылок C++ оставляет желать... Вот посмотрим простой пример:
void DoString(string&& str) { }
. . .
DoString("I'm an rvalue string");
Все прекрасно компилируется, как и должно. Теперь попробуем так:
string s { "I'm an lvalue string" };
DoString(s);
Ошибка компиляции (как и должно быть):
error C2664: 'void DoString(std::string &&)': cannot convert argument 1 from 'std::string' to 'std::string &&'
note: You cannot bind an lvalue to an rvalue reference
Теперь попробуем сделать чуть сложнее:
string&& rs = string("I'm an rvalue string");
DoString(rs);
Та же самая ошибка компиляции, что и выше! Не могу сконвертировать аргумент из std::string
в std::string &&
блаблабла. Но ведь rs
- это rvalue. И если навести на нее курсор, студия показывает тип std::string &&
. Откуда вылезло lvalue?
Была мысль, что это потому, что rs
- ссылка на x-value, а не на pr-value. Однако функция std::move
тоже возвращает ссылку на x-value, но при этом вызов
DoString(std::move(s));
прекрасно компилируется.
Так что вопросы у меня появились такие:
1) Что происходит при присваивании string&& rs = string("I'm an rvalue string");
?
2) Что такое rs
и каким образом в виде аргумента функции она превращается в lvalue?
Видимо вас вводит в заблуждения терминолигия С++. Дело в том, что термин rvalue
может использоваться для обозначения двух разных, независимых понятий:
str
, объявленной как string && str
в вашем примереstd::move(s)
(xvalue) или string("I'm an rvalue string")
(prvalue) в вашем примереТак вот, чтобы выражение подходило под тип rvalue reference оно должно иметь категорию rvalue, а не тип rvalue reference. В записи DoString(rs);
тип rs
будет rvalue reference, а категория выражения - нет.
Теперь попробуем сделать чуть сложнее:
string&& rs = string("I'm an rvalue string");
DoString(rs);
Та же самая ошибка компиляции, что и выше! Не могу сконвертировать аргумент из std::string
в std::string
&& блаблабла.
Разница между lvalue-ссылками и rvalue-ссылками в том, какими выражениями их можно инициализировать.
Сами ссылки (обоих видов) всегда считаются lvalue.
Поэтому нам, например, нужен std::forward
для универсальных ссылок.
Что происходит при присваивании string&& rs = string("I'm an rvalue string");
Создается временный безымянный объект типа string
. В обычных условиях он был бы тут же разрушен, но так как вы инициализировали им ссылку, для него происходит продление времени жизни (lifetime extension). Он будет разрушен вместе со ссылкой.
(Если я правильно помню, временный объект создается как prvalue, а затем за счет temporary meterialization превращается в xvalue. И то, и другое - это подкатегории rvalue.)
rs - это lvalue, вы же сохранили строку в переменной. Смотрите определения тут http://eel.is/c++draft/basic.lval#1
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Вот такая вот простенькая программ, окно отслеживает позицию мыши и рисует ее координаты рядом с нейНо заметил интересный эффект мигания...
Столкнулся с такой проблемой, что не могу одновременно воспроизводить файл по ссылке и визуализировать егоОтдельно визуализация загруженного...