2011-06-09 12 views
28

Recientemente he leído que tiene sentido al volver por el valor de una función para calificar el tipo de retorno const de tipos no incorporadas, por ejemplo:¿Cuáles son los casos de uso para tener un retorno de función por valor de const para tipo no incorporado?

const Result operation() { 
    //..do something.. 
    return Result(..); 
} 

estoy luchando para entender los beneficios de esto, una vez que el el objeto ha sido devuelto, seguramente es la elección de quienes llaman para decidir si el objeto devuelto debe ser const?

Respuesta

30

Básicamente, hay un ligero problema de idioma aquí.

std::string func() { 
    return "hai"; 
} 

func().push_back('c'); // Perfectly valid, yet non-sensical 

Devolución de const rvalues ​​es un intento de evitar dicho comportamiento. Sin embargo, en realidad, hace mucho más daño que bien, porque ahora que las referencias rvalue están aquí, vas a evitar la semántica de movimiento, lo cual es una mierda, y el comportamiento anterior probablemente se evitará mediante el uso juicioso de rvalue y lvalue *this sobrecarga. Además, tendrías que ser un poco idiota para hacer esto de todos modos.

+0

¿Estás seguro de que marcar el valor r como const evita la semántica del movimiento? Mi versión de clang permite llamar a un constructor de movimiento personalizado con un valor de configuración (aunque no permite que una referencia de valor variable no condicional se vincule a él, así que no estoy del todo seguro de lo que está sucediendo). –

+0

@ John Calsbeek: ¿Cómo se puede pasar de un valor constante? No puedes modificarlo, porque es const. – Puppy

+0

@John: ¿Pero puede su constructor de const move realmente realizar el movimiento? P.ej. supongamos que tu clase tiene un puntero sin formato que debe ser liberado. En el constructor de movimientos, copie el puntero, pero también debe establecer la copia en el objeto RHS en NULL para que no se elimine por partida doble. Pero si es un valor de configuración, no puede modificarlo ... – HighCommander4

10

No hay ningún beneficio al devolver por valor. No tiene sentido.

La única diferencia es que se evita que la gente se lo emplea como valor-I:

class Foo 
{ 
    void bar(); 
}; 

const Foo foo(); 

int main() 
{ 
    foo().bar(); // Invalid 
} 
+0

Esto es realmente incorrecto. No impide que las personas lo usen como un lvalue en absoluto. Impide que las personas lo usen como un objeto no const. Éstas son dos cosas completamente diferentes. – Puppy

10

Ocasionalmente es útil. Vea este ejemplo:

class I 
{ 
public: 
    I(int i)     : value(i) {} 
    void set(int i)   { value = i; } 
    I operator+(const I& rhs) { return I(value + rhs.value); } 
    I& operator=(const I& rhs) { value = rhs.value; return *this; } 

private: 
    int value; 
}; 

int main() 
{ 
    I a(2), b(3); 
    (a + b) = 2; // ??? 
    return 0; 
} 

Tenga en cuenta que el valor devuelto por operator+ normalmente sería considerado un temporal. Pero está siendo claramente modificado. Eso no es exactamente deseado.

Si declara el tipo de devolución de operator+ como const I, no se compilará.

+0

Artículo 3 del "C++ efectivo" – pic11

0

Como nadie lo ha señalado aún, es bastante útil en objetos proxy, con casos de uso real.

Imagínese que usted está escribiendo un tipo matrix y desea utilizar de esta manera:

Matrix<3, 3> matrix; 
Matrix<1, 3> rowVector; 

/* assign a row */ 
matrix[1] = rowVector; 

Para ello, se vuelve un nuevo objeto proxy de operator[]. Cuando se opera en un const Matrix, aún desea poder acceder a los datos a través del proxy, pero prohíbe el acceso de escritura. Esto se puede hacer volviendo por el valor const.

template<size_t Rows, size_t Cols> 
class Matrix { 
    class RowProxy { 
     Matrix& m; 
     size_t row; 
     /* ... operator= and operator[] */ 
    }; 

    RowProxy operator[](size_t row) { return RowProxy(*this, row); } 
    const RowProxy operator[](size_t row) const { return RowProxy(*this, row); } 
    // ^~~~ here the const is very useful and important 
}; 
Cuestiones relacionadas