Mirando este artículo sobre la seguridad de concurrencia de Rust:
http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html
Me preguntaba cuántas de estas ideas se pueden lograr en C ++ 11 (o más reciente). En particular, ¿puedo crear una clase de propietario que transfiera la propiedad a cualquier método al que se pueda pasar? Parece que C ++ tiene tantas formas de pasar variables que sería imposible, pero ¿tal vez podría poner algunas restricciones en la clase o plantilla para asegurar que se ejecute algún código de plantilla con cada paso de método?
concurrency
c++11
rust
Brannon
fuente
fuente
&
no requieren ningún tipo de promoción para ser utilizados. Si intenta obtener un&mut
tiempo, todavía tiene otra referencia (mutable o no) al mismo elemento, no podrá compilar.RefCell<T>
mueve el cheque al tiempo de ejecución, por lo que obtendrá pánico si intenta.borrow_mut()
algo que ya tiene un activo.borrow()
o.borrow_mut()
. Rust también tieneRc<T>
(puntero de propiedad compartido) y su hermanoWeak<T>
, pero se trata de propiedad, no de mutabilidad. Pegue unRefCell<T>
dentro de ellos para la mutabilidad.Respuestas:
C ++ tiene tres formas de pasar parámetros a una función: por valor, por referencia de valor y por referencia de valor. De estos, pasar por valor crea propiedad en el sentido de que la función llamada recibe su propia copia, y pasar por rvalue reference indica que el valor puede ser consumido, es decir, el llamador ya no lo usará. Pasar por referencia de valor significa que el objeto se toma prestado temporalmente de la persona que llama.
Sin embargo, estos tienden a ser "por convención" y no siempre pueden ser verificados por el compilador. Y puede convertir accidentalmente una referencia de valor en una referencia de valor utilizando
std::move()
. Concretamente, hay tres problemas:Una referencia puede sobrevivir al objeto al que hace referencia. El sistema de por vida de Rust evita esto.
Puede haber más de una referencia mutable / no constante activa en cualquier momento. El comprobador de préstamos de Rust lo impide.
No puede optar por no recibir referencias. No puede ver en un sitio de llamadas si esa función crea una referencia a su objeto, sin conocer la firma de la función llamada. Por lo tanto, no puede evitar de manera confiable las referencias, ni eliminando ningún método especial de sus clases ni auditando el sitio de la llamada para el cumplimiento de alguna guía de estilo de "no referencias".
El problema de por vida es sobre la seguridad básica de la memoria. Por supuesto, es ilegal usar una referencia cuando el objeto referenciado ha expirado. Pero es muy fácil olvidarse de la vida útil cuando almacena una referencia dentro de un objeto, en particular cuando ese objeto sobrevive al alcance actual. El sistema de tipo C ++ no puede explicar esto porque no modela la vida útil de los objetos.
El
std::weak_ptr
puntero inteligente codifica la semántica de propiedad de forma similar a una referencia simple, pero requiere que el objeto referenciado se gestione mediante unshared_ptr
, es decir, se cuente por referencia. Esta no es una abstracción de costo cero.Si bien C ++ tiene un sistema constante, esto no rastrea si un objeto puede modificarse, sino que rastrea si un objeto puede modificarse a través de esa referencia en particular . Eso no proporciona suficientes garantías para la "concurrencia intrépida". Por el contrario, Rust garantiza que si hay una referencia mutable activa que es la única referencia ("Soy el único que puede cambiar este objeto") y si hay referencias no mutables, entonces todas las referencias al objeto no son mutables ("Aunque puedo leer del objeto, nadie puede cambiarlo").
En C ++, puede sentirse tentado a proteger el acceso a un objeto a través de un puntero inteligente con un mutex. Pero como se discutió anteriormente una vez que tenemos una referencia, puede escapar de su vida útil esperada. Por lo tanto, dicho puntero inteligente no puede garantizar que sea el único punto de acceso a su objeto administrado. Tal esquema en realidad puede funcionar en la práctica porque la mayoría de los programadores no quieren sabotearse a sí mismos, pero desde el punto de vista del sistema de tipos esto todavía es completamente incorrecto.
El problema general con los punteros inteligentes es que son bibliotecas además del lenguaje central. El conjunto de características principales del lenguaje permite estos punteros inteligentes, por ejemplo,
std::unique_ptr
necesita constructores de movimiento. Pero no pueden solucionar las deficiencias dentro del lenguaje central. Las habilidades para crear referencias implícitamente cuando se llama a una función y para tener referencias colgantes juntas significan que el lenguaje central de C ++ no es sólido. La incapacidad de limitar las referencias mutables a una sola significa que C ++ no puede garantizar la seguridad contra las condiciones de carrera con ningún tipo de concurrencia.Por supuesto, en muchos aspectos, C ++ y Rust son más parecidos de lo que son diferentes, en particular con respecto a sus conceptos de vidas de objetos determinadas estáticamente. Pero si bien es posible escribir programas C ++ correctos (siempre que ninguno de los programadores cometa errores), Rust garantiza la corrección con respecto a las propiedades discutidas.
fuente