Pregunta

Una de las nuevas características interesantes del próximo estándar C ++, C ++ 0x, son & "; referencias de valor. &"; Una referencia rvalue es similar a una referencia lvalue (normal), excepto que puede vincularse a un valor temporal (normalmente, un temporal solo puede vincularse a una referencia const):

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

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

Entonces, ¿por qué inventaron un tipo completamente nuevo, en lugar de simplemente eliminar las restricciones a las referencias normales para permitir que se unan a los temporales?

¿Fue útil?

Solución

Sería inútil. Cambiaría la cosa en la función, y el cambio se perdería inmediatamente porque la cosa era en realidad temporal.

La razón del nuevo tipo se debe a la necesidad de poder decidir qué es realmente un valor y qué no. Solo entonces puedes usarlos para las cosas geniales que se usan.

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));
}

Ahora, si tiene un valor de r y lo pasa a toupper, el valor de r puede modificarse directamente, porque sabemos que el temporal es algo desechable de todos modos, por lo que también podemos cambiarlo y no es necesario copiar eso. Además, se usa la misma observación para la cosa llamada constructores de movimiento y asignación de movimiento. El lado derecho no se copia, pero sus cosas simplemente se roban y se mueven a *this.

Si dijera que los valores pueden unirse a referencias de valor no constantes, entonces no tendría forma de averiguar si eso hace referencia a un valor (objeto nombrado) o un valor (temporal) al final.


Probablemente sea más poco conocido, pero útil de todos modos, puede poner lvalue o rvalue ref-qualifiers en una función miembro. Aquí hay un ejemplo, que naturalmente extiende la semántica existente de las referencias rvalue al parámetro de objeto implícito:

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

Ahora, ya no puedes decir

string() = "hello";

Lo cual es confuso y realmente no tiene sentido la mayor parte del tiempo. Lo que hace el & anterior es decir que el operador de asignación solo se puede invocar en valores. Lo mismo se puede hacer para los valores, poniendo &&.

Otros consejos

Porque agregar un nuevo tipo de referencia le permite escribir dos sobrecargas de un método:

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

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

La versión que acepta el nuevo tipo de referencia puede modificar la variable que recibe, porque esa variable no se utilizará en ningún otro lado. Entonces puede & "; Robar &"; el contenido de la misma.

Esta es la razón por la que se agregó esta característica; retener un tipo de referencia no lograría el objetivo deseado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top