Как можно получить ссылку на rvalue?
Я использовал std::move
а также std::forward
в C++. Мой вопрос: как эти функции на самом деле реализуются стандартной библиотекой?
Если lvalue - это то, что вы можете получить по адресу, а rvalue не является исключительно lvalue, как вы можете на самом деле реализовать эти ссылки?
Разве эти новые возможности позволяют что-то вроде:
auto x = &(3);
или что-то типа того? Можете ли вы получить ссылку на значение, которое не просто std::move
/forward
вернул lvalue?
Надеюсь, эти вопросы имеют смысл. Я не смог найти хорошую информацию в Google, только учебники по идеальной пересылке и т. Д.
3 ответа
Я не могу вызвать функцию: void foo(string* bar)
как это: foo(&string("Hello World!"))
или я получаю ошибку:
ошибка: получение временного адреса
Я также не могу вызвать функцию: void foo(string& bar)
как это: foo(string("Hello World!"))
или я получаю ошибку:
ошибка: неверная инициализация неконстантной ссылки типа 'std::string& {aka std::basic_string&}' из значения типа 'std::string {aka std::basic_string}'
Что C++11 предоставил мне возможность сделать, так это сделать ссылку на rvalue, чтобы я мог вызвать функцию: void foo(string&& bar)
как это: foo(string("Hello World!"));
Кроме того, внутренне foo
Я могу получить адрес объекта, переданного по ссылке rvalue:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
Похоже, у ОП действительно хороший контроль над значениями. Но это их объяснение было полезно для меня, а может и для других. В нем подробно рассказывается о том, почему C++03 допускает постоянные ссылки на rvalue по сравнению с C++11 ссылками на rvalue.
Как можно получить ссылку на rvalue?
Концептуально выражение rvalue создает временный объект или иногда обозначает существующий объект. Это может быть связано со ссылкой, как и любой другой объект; но, чтобы избежать путаницы, язык допускает это только для const
lvalue ссылки.
Я использовал std::move и std::forward в C++. Моя проблема в том, как это на самом деле реализуется компилятором?
move
просто возвращает rvalue ссылку на свой аргумент, эквивалентный
static_cast<typename remove_reference<T>::type&&>(t)
Результатом вызова функции является rvalue (в частности, xvalue), поэтому его можно привязать к ссылке rvalue, где аргумент функции не может. Это позволяет вам явно перейти от lvalue, используя move
преобразовать его в значение, не позволяя случайно от него переместиться.
forward
аналогично, но перегружен для возврата ссылки rvalue на ссылку rvalue или rvalue и ссылку lvalue на что-либо еще.
Если значение l является чем-то, вы можете получить адрес
Это более или менее правильно. Официальное определение заключается в том, что выражение "обозначает функцию или объект", и это те вещи, которые имеют адреса.
и значение r исключительно не является значением l
На самом деле, нет. Упрощенно говоря, выражение является либо lvalue, либо rvalue, но может быть преобразовано из одного в другое. Значение l может быть неявно преобразовано в значение r; преобразование в другую сторону может быть сделано с помощью приведения, как move
делает.
как вы можете реализовать эти ссылки?
Как и любая другая ссылка - как псевдоним или указатель на объект, с которым он связан. Единственное отличие состоит в том, какие виды выражений могут использоваться для обозначения (и, возможно, создания) объекта, который связан с ссылкой.
Разве эти новые возможности позволяют что-то вроде
auto x = &(3);
Это пытается получить адрес rvalue напрямую, что недопустимо. Поскольку речь идет о ссылках, а не указателях, допустимо следующее, связывающее ссылку с временным объектом (время жизни которого увеличивается для соответствия ссылке):
auto && rvalue = 3;
auto const & const_lvalue = 3;
пока не разрешено связывать его с неконстантной ссылкой lvalue
auto & lvalue = 3; // ERROR
В основном, магия компилятора. Стандарт описывает правила, производитель компиляторов просто должен выяснить, как реализовать правила.
На практике ссылки либо оптимизируются, либо реализуются как указатель на уровне процессора.
std::move
не очень особенный в этом смысле. Он имеет ссылку lvalue в качестве входных данных и ссылку rvalue в качестве выходных данных. Компилятор просто должен применить правила ввода rvalue к входным данным.
Точно так же цель std::forward<T>
это просто сказать компилятору применить другой набор правил к аргументу, правила, которые должны быть определены так, чтобы идеальная пересылка работала. Сама функция ничего не делает.