c++ - constint - const javascript
¿El propósito de regresar por valor de const? (6)
C ++ 11 lo hace bastante útil con objetos de solo movimiento. Por ejemplo:
const std::unique_ptr<T> myFunc();
unique_ptr
es un tipo que no se puede copiar; solo se puede mover Pero no puedes llamar a std::move
en un tipo const
. Por lo tanto, la única forma de almacenar esto es const&
o const&&
:
const std::unique_ptr<T> &ptr = myFunc();
Como es un const unique_ptr
, no se puede mover desde. Tampoco se puede copiar de. Lo que significa que es muy difícil almacenar esto en cualquier lugar a largo plazo. Puedes ponerlo en la pila. Pero hacer que sea miembro de una clase es imposible (sin invocar un comportamiento indefinido).
De esta manera, uno puede asegurarse de que el puntero no se almacena a largo plazo. Esto le permite a uno crear una versión especializada de unique_ptr
cuyo eliminador no elimina la memoria. De esta forma, una función puede devolver un puntero sabiendo que el usuario no puede almacenarlo en ningún lugar.
Por supuesto, esto también hace que sea difícil para quien llama devolver el valor. Entonces hay desventajas.
Esta pregunta ya tiene una respuesta aquí:
¿Cuál es el propósito de la const en esto?
const Object myFunc(){
return myObject;
}
Acabo de empezar a leer Effective C ++ y el artículo 3 lo defiende y una búsqueda en Google recoge sugerencias similares, pero también contraejemplos. No puedo ver cómo usar const aquí alguna vez sería preferible. Suponiendo que un retorno por valor es deseable, no veo ninguna razón para proteger el valor devuelto. El ejemplo dado de por qué esto podría ser útil es prevenir bool involuntarios del valor de retorno. El problema real entonces es que las emisiones implícitas de bool deberían evitarse con la palabra clave explícita.
El uso de const aquí evita el uso de objetos temporales sin asignación. Entonces no pude realizar expresiones aritméticas con esos objetos. No parece que haya un caso en el que un const sin nombre sea útil.
¿Qué se gana al usar const aquí y cuándo sería preferible?
EDITAR: Cambia el ejemplo aritmético a cualquier función que modifique un objeto que tal vez quieras realizar antes de una tarea.
En la situación hipotética en la que podría realizar una operación no const potencialmente costosa en un objeto, el retorno por valor constante le impide llamar accidentalmente esta operación en forma temporal. Imagine que +
devolvió un valor no const, y podría escribir:
(a + b).expensive();
Sin embargo, en la era de C ++ 11, se recomienda encarecidamente devolver los valores como no const para que pueda aprovechar al máximo las referencias rvalue, que solo tienen sentido en valores r no constantes.
En resumen, hay una razón fundamental para esta práctica, pero es esencialmente obsoleta.
Se asegura de que el objeto devuelto (que es un RValue en ese punto) no se puede modificar. Esto asegura que el usuario no puede hacer piensa así:
myFunc() = Object(...);
Eso funcionaría muy bien si myFunc
regresara por referencia, pero es casi seguro que es un error cuando se devuelve por valor (y probablemente no sea capturado por el compilador). Por supuesto, en C ++ 11 con sus valores r, esta convención no tiene tanto sentido como antes, ya que un objeto const no se puede mover, por lo que puede tener efectos bastante pesados sobre el rendimiento.
Se podría usar como una función de contenedor para devolver una referencia a un tipo de datos constante privado. Por ejemplo, en una lista vinculada tiene las constantes de cola y cabeza, y si desea determinar si un nodo es un nodo de cola o cabeza, entonces puede compararlo con el valor devuelto por esa función.
Aunque cualquier optimizador lo optimizaría de todos modos ...
myObject podría ser un puntero. El ''const'' protege el valor apuntado por myObject.
No tiene pointless devolver un valor const
de una función.
Es difficult lograr que tenga algún efecto en tu código:
const int foo() {
return 3;
}
int main() {
int x = foo(); // copies happily
x = 4;
}
and :
const int foo() {
return 3;
}
int main() {
foo() = 4; // not valid anyway for built-in types
}
// error: lvalue required as left operand of assignment
Aunque puede observar si el tipo de devolución es un tipo definido por el usuario :
struct T {};
const T foo() {
return T();
}
int main() {
foo() = T();
}
// error: passing ‘const T’ as ‘this’ argument of ‘T& T::operator=(const T&)’ discards qualifiers
es cuestionable si esto beneficia a alguien.
Devolver una referencia es diferente, pero a menos que Object
sea un parámetro de plantilla, no lo está haciendo.