Почему ссылка rvalue в C++0x не используется по умолчанию?

StackOverflow https://stackoverflow.com/questions/844241

  •  20-08-2019
  •  | 
  •  

Вопрос

Одной из замечательных новых функций готовящегося к выходу стандарта C++, C++0x, являются «ссылки rvalue». Ссылка rvalue похожа на ссылку lvalue (normal), за исключением того, что она может быть привязана к временному значению (обычно временная ссылка может быть привязана только к const ссылка):

void FunctionWithLValueRef(int& a) {...}
void FunctionWithRValueRef(int&& a) {...}

int main() {
     FunctionWithLValueRef(5); // error, 5 is a temporary
     FunctionWithRValueRef(5); // okay
}

Так почему же они изобрели совершенно новый тип вместо того, чтобы просто снять ограничения на обычные ссылки, чтобы позволить им привязываться к временным объектам?

Это было полезно?

Решение

Это было бы бессмысленно.Вы бы изменили объект в функции, и это изменение было бы немедленно потеряно, потому что на самом деле объект был временным.

Причина создания нового типа связана с необходимостью решать, что на самом деле является значением r, а что нет.Только тогда вы действительно сможете использовать их для тех крутых вещей, которые они используют.

string toupper(string && s) { // for nonconst rvalues
    for(char &c : s) make_uppercase(c);
    return move(s); // move s into a returned string object
}

string toupper(string const& s) { // for the rest
    // calls the rvalue reference version, by passing 
    // an rvalue copy.
    return toupper(string(s));
}

Теперь, если у вас есть какое-то значение rvalue и вы передаете его toupper, это значение rvalue можно изменить напрямую, потому что мы знаем, что временное значение в любом случае является выбрасываемым, поэтому мы также можем просто изменить его и не копировать его.Кроме того, то же наблюдение используется для вещей, называемых конструкторами перемещения и присваиванием перемещения.Правая часть не копируется, а ее элементы просто украдены и перенесены в *this.

Если бы вы сказали, что значения rvalue могут привязываться к неконстантным ссылкам lvalue, то у вас не было бы возможности выяснить, ссылается ли это на lvalue (именованный объект) или на rvalue (временное) в конце.


Вероятно, об этом мало что известно, но в любом случае полезно: вы можете поместить ref-квалификаторы lvalue или rvalue в функцию-член.Вот пример, который естественным образом расширяет существующую семантику ссылок rvalue на неявный параметр объекта:

struct string {
    string& operator=(string const& other) & { /* ... */ }
};

Теперь ты больше не можешь сказать

string() = "hello";

Это сбивает с толку и большую часть времени не имеет смысла.Что за & выше говорит о том, что оператор присваивания может быть вызван только для lvalues.То же самое можно сделать и для rvalue, поставив &&.

Другие советы

Потому что добавление нового типа ссылки позволяет вам написать две перегрузки метода:

void CopyFrom(MyClass &&c)
{
    dataMember.swap(c);
}

void CopyFrom(const MyClass &c)
{
    dataMember.copyTheHardWay(c);
}

Версия, которая принимает ссылку нового типа, может изменять полученную переменную, поскольку эта переменная больше нигде не будет использоваться.Таким образом, он может «украсть» его содержимое.

Это единственная причина, по которой была добавлена ​​эта функция;сохранение одного типа ссылок не достигнет желаемой цели.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top