Подтвердить что ты не робот

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

Одной из замечательных новых функций предстоящего стандарта С++, С++ 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
}

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

4b9b3361

Ответ 1

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

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

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 может быть напрямую изменено, потому что мы знаем, что временное - это отбрасывание, так что мы можем просто изменить его и не нужно копировать Это. Кроме того, одно и то же наблюдение используется для объекта, называемого move-constructors и move-assign. Правая сторона не копируется, но ее вещи просто украдены и перемещены на *this.

Если бы вы сказали, что rvalues ​​могут связываться с неконстантными ссылками lvalue, тогда у вас не будет возможности выяснить, ссылается ли это на значение lvalue (named object) или rvalue (временное) в конце.


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

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

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

string() = "hello";

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

Ответ 2

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

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

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

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

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