¿Todos los objetos en C ++ son mutables si no se indica lo contrario?
En Python y Javascript no puedo cambiar cadenas, tuplas, unicodes. Me preguntaba si hay algo en C ++ que sea inmutable o si cada objeto es mutable y tengo que usar el const
calificador de tipo para hacerlo inmutable.
Respuestas:
La inmutabilidad ha sido bien entendida por algún tiempo. Python, Java y C ++ tienen diferentes modelos de memoria que dificultan las comparaciones directas. El autor del artículo que citó originalmente no parece conocer C ++.
Al igual que en Python, Java y la mayoría de los lenguajes de paradigmas múltiples, C y C ++ permiten la mutabilidad de forma predeterminada. Esto es lo que los programadores suelen querer: si tengo una
String x
variable, quiero poder asignar un nuevo valorx = "foo"
.El sistema const en C y C ++ permite una gran cantidad de inmutabilidad matizada que falta en Python, Java e incluso Scala. Si una función C ++ toma a
const std::string&
o aconst char*
, promete (y el compilador se asegura, hasta cierto punto), que esta función no cambiará (¡no puede!) El contenido de esa cadena. Dado un objeto const, solo podemos invocar métodos de ese objeto que también están marcados como const. Si una clase C ++ solo tiene miembros públicosconst
, entonces el objeto es efectivamente inmutable.Sin embargo, esto a veces es confuso ya que en C y C ++ los objetos son ubicaciones de memoria y las variables son nombres para ubicaciones de memoria. Por el contrario, las variables en Python y Java son nombres para punteros a objetos. En un lenguaje con semántica de referencia,
x = y
significa "hacer que x apunte al mismo objeto que y". Como solo estamos copiando punteros, esto es posible con objetos inmutables. En un lenguaje con semántica de valor como C ++, significa "actualizar el contenido dex
con el contenido dey
". Por lo tanto, si se desea la reasignación de una variable en C o C ++, la variable puede no tener un tipo constante. Para hacer esto con objetos inmutables, tendríamos que usar un puntero explícitamente.Que Java y Python utilicen objetos de cadena inmutables es una decisión de diseño fundamental, pero no está directamente relacionado con los beneficios de la inmutabilidad en un entorno de subprocesos múltiples. Una razón es que los literales de cadena en el código fuente se pueden agrupar, lo que reduce la cantidad de objetos. Esto también es posible en C / C ++. En C ++, el literal
"foo"
tiene tipoconst char[4]
(el cuarto carácter es la terminación'\0'
). Otra razón es que las entradas en conjuntos y claves en dictos / mapas no deben cambiarse. Dado que las cadenas se usan de forma generalizada como claves dict (la mayoría de los objetos de Python son un dict), la inmutabilidad elimina una fuente común de errores. En Java, otra razón para las cadenas inmutables es el modelo de seguridad de Java. Todas estas razones no tienen ninguna relación con el subprocesamiento múltiple.Si Java se construyera con la inmutabilidad en mente, el lenguaje habría tenido un aspecto muy diferente. Si bien está inspirado en C ++, los diseñadores se esforzaron por crear un lenguaje mucho más simple, deshacerse de la constante es uno de esos pasos. Lo equivalente de Java a una referencia constante de C ++ es un adaptador o decorador que implementa cualquier método de mutación como
throws new NotImplementedException()
, y reenvía las llamadas de método no mutante a la colección real. El hecho de que todas las interfaces de la colección java.util impliquen mutabilidad es una clara señal de que no se esforzaron por un lenguaje de inmutabilidad primero.La solución que Java presentó para resolver los problemas de concurrencia no era la inmutabilidad, sino el bloqueo generalizado. Cada objeto contiene un mutex que puede usarse para
synchronized
bloques o métodos completos. Como resultado, eso no es bueno para el rendimiento, no escala muy bien y es bastante propenso a errores: aún debe lidiar con un estado global mutable.fuente
mut
palabra clave y el compilador señala una mutabilidad innecesaria) tienden a respaldar mi hipótesis: en Rust, tienes muchos máslet
enlaces que los que tieneslet mut
.for x in 1..10
que no se utilizalet mut
para definir la variable del bucle, pero obviamente requiere algo de mutabilidad (solo a nivel del bucle, no dentro del cuerpo del bucle).const T o = [&]{T o; o.init(...); return o;}();
... yay para API que no fueron diseñadas teniendo en cuenta la inmutabilidad.Casi. El lenguaje en sí trata todo como mutable a menos que lo use
const
, pero aún es posible construir objetos inmutables sin decirle al compilador que son inmutables, simplemente no proporcionando una forma de mutarlos.Por ejemplo, toma esta clase:
Las instancias de
MyClass
son inmutables, porque no hay forma de mutarlas, pero en ninguna parte del código se dice que son inmutables. (Esta es la misma forma en que las instancias de laString
clase de Java son inmutables)fuente
delete
de que el operador de asignación de copia aquí también asegure que uno no puede asignar desde una referencia de valor mediante la operación de asignación de movimiento?value
const y declarargetValue()
una función const.No, hay una excepción: Lambdas y, por extensión, los objetos que capturan son inmutables por defecto:
Entonces, en lugar de agregar
const
para hacerlo inmutable, agregamutable
para que no lo seaconst
.fuente