Punteros en C # Unity

8

Hola, acabo de aprender sobre punteros recientemente y me pregunto cómo puedo usarlos en c # (acabo de aprender sobre ellos en c ++) en unidad. Sin embargo, tengo algunas preguntas.

  1. Los punteros usan programación de bajo nivel para encontrar posiciones de diferentes valores en la computadora, entonces, ¿eso significa que puede acceder al valor de una variable desde cualquier script?
  2. Si es así, ¿cómo invoco la ubicación de una variable solo con su código de ubicación?
  3. ¿Hay alguna diferencia discernible entre los punteros en C # y C ++ que deba saber?
  4. ¿Cómo puedo usar punteros con los tipos de variables en Unity (Vector3s, Transforms, GameObjects, etc.)?

Hay muchas más preguntas que probablemente debería y me gustaría hacer si tiene alguna información adicional o fuentes.

Ryan Henry
fuente

Respuestas:

6

En general, para C # y específicamente para Unity, le recomendaría que no lo haga ... pero si realmente quisiera o tuviera una buena razón, podría hacerlo.

En C # necesitaría familiarizarse con lo que se llama código inseguro . ¿Asustado todavía?

En Unity, deberías habilitar el modo de compilación inseguro para que no puedas usar el reproductor web si planeaste eso. Puedes leer más aquí o aquí .

Básicamente, C # se diseñó con un recolector de basura como lo son muchos lenguajes de secuencias de comandos. La idea general es tratar de abstraer la noción de gestión de memoria para simplificar el desarrollo. Todavía puede terminar con pérdidas de recursos si no anula sus objetos. Sinceramente, no soy un gran defensor de los GC y preferiría los métodos RAII , pero este es el mundo en el que vivimos.

Sin embargo, la mayoría de los desarrolladores de C ++ también estarían de acuerdo en que no debería usar punteros directamente de todos modos y preferiría usar un tipo diseñado por RAII, también conocido como punteros inteligentes . Si estás en tierra C, entonces los punteros probables son una segunda naturaleza para ti, pero incluso así, es útil abstraerlos hasta cierto punto.

Si los usa en C #, tenga en cuenta que existe un potencial muy real que podría agregar vulnerabilidades de seguridad o errores realmente desagradables y difíciles de rastrear. También deberá tener en cuenta que debe tener cuidado de no hacer referencia a objetos que el GC pueda mover. Tenga en cuenta el uso de la declaración fija aquí .

También puede usar Punteros en Unity escribiendo un complemento nativo . Esto nuevamente descartará las compilaciones de jugadores web, pero la nueva función HTML5 funciona basada en emscripten, por lo que si planea usar eso, probablemente podría hacerlo si tiene cuidado. Los complementos nativos le permiten extender Unity por plataforma. Escribí un complemento nativo para comunicarse con algunos microcontroladores a través de una conexión en serie, por ejemplo.

Entonces, para resumir, definitivamente debe preguntarse por qué quiero usar punteros en C # en Unity. Si solo quieres hacerlo por diversión ... Déjate llevar.

Editar: Lamento haber ofendido a alguien, ya que sé que mis pensamientos sobre GC no son de la opinión popular en este momento.

Si realmente lee mi respuesta, notará que no llamo a C # un lenguaje de script. Lo comparo con "muchos lenguajes de secuencias de comandos", sin embargo, en el contexto de Unity se usa mucho como lenguaje de secuencias de comandos. Es algo así como un DSL para Unity, por así decirlo. Muchas veces lo verá incluso denominado Unity Script en este contexto (esto es principalmente en referencia a la alternativa Javascript de Unity a C #). Si pones LLVM en tu canalización, puedes compilarlo en código nativo para la plataforma directamente ... ¿cómo lo llamarías? Así que realmente no quería dividir los pelos aquí.

Muchas grandes referencias a la ingeniería de software están llenas de opiniones:

Efectiva C ++ , más eficaz C ++ , C ++ FAQ , efectiva C # , moderno diseño de C ++ , patrones de diseño ... Y muchos otros. No creo que esto haga que los argumentos sean menos creíbles si van seguidos de una explicación reflexiva.

Realmente no estaba del todo diciendo "¡No uses punteros nunca!" . De hecho, todavía los uso desnudos en ocasiones. Dije "en general" como en "prefiero usar código seguro a código inseguro en C #". Hay situaciones en las que puede ser beneficioso, y esa es una de las características realmente poderosas de C # para elegir y elegir sus herramientas. C # incluso le permite tener transparencia en el proceso de GC hasta cierto punto, los lenguajes como Dart no lo hacen y pueden provocar pérdidas de recursos con mucha facilidad. Claro, si usted es el único desarrollador de un pequeño proyecto, probablemente no sea un problema. Si está en un equipo de digamos 10+ con cientos de miles de líneas de código, entonces puede ser complicado.

Simplemente quería que el lector tuviera precaución al usar punteros desnudos. Es similar a decir que tenga mucho cuidado cuando trabaje con la red eléctrica. No digo que no seas electricista, solo que si haces el movimiento equivocado y no lo tratas con respeto, estás muerto.

Me gusta el ejemplo dado por Lasse en el que el rendimiento puede haber dictado la necesidad.

Matthew Sanders
fuente
1
C # no es un lenguaje de secuencias de comandos, aunque puede usarse para eso. Java también tiene un GC y tampoco es un lenguaje de script. Responder con su propia opinión lo que es mejor en general, no es la respuesta objetiva que estamos buscando en este sitio. Para un propósito específico, algo como códigos y punteros inseguros puede ser realmente eficiente.
Lasse
1
No entiendo por qué se rechaza esta respuesta: es muy informativa y muestra mucha investigación / conocimiento y enlaces a lecturas adicionales. Especialmente para @Lasse, ¿qué es el lenguaje de script? Por supuesto, sería más preciso decir "lenguaje que se usa para la creación de secuencias de comandos en la unidad", pero no veo muchas razones para rechazar porque Matthew omitió 7 palabras obvias y usó un término (sobre) simplificado.
wondra
@wondra hice una votación porque la respuesta no es obvia que hay lugares donde los punteros se pueden usar muy bien en C #. Todo depende del propósito y la plataforma de destino. De hecho, la respuesta está tratando de asustar a todos para que no usen punteros.
Lasse
1
@wondra Esta respuesta apenas responde a la pregunta. Todo lo que hace es decirle que no use punteros. Esta sección de comentarios no es el lugar adecuado para discutir esto. Puedes unirte al chat si crees que tienes más argumentos.
Lasse
1
@Lasse no puede convencerte y no es mi lucha, pero al ver tu respuesta, escribiste exactamente lo mismo que esta respuesta (que se publicó antes), además, incluso incluiste solo un subconjunto (= menos información) sobre el tema como lo hizo esta respuesta.
wondra
6

C # usa referencias para pasar objetos que no son tipos de valor . Esto significa que todo generalmente se pasa por referencia. Si desea pasar un tipo de valor por referencia, puede usar la palabra clave ref . La diferencia entre un tipo de referencia y un tipo de valor es que, dependiendo de qué tan grande sea el tipo de valor, generalmente requiere más memoria copiada cuando se pasa a una función. Una referencia es solo 32 bits o 64 bits , o 4 bytes u 8 bytes. Puede obtener más rendimiento de su código en bucles muy ajustados si usa referencias en lugar de simplemente copiar todos los datos que contienen las variables de tipo de valor, suponiendo que sean mayores de 4 u 8 bytes.

Por ejemplo, en Unity, cualquier objeto MonoBehaviour (clase) es un tipo de referencia, y cualquier objeto Vector3 (estructura) es un tipo Value.

También hay bloques de código inseguro que le permitirán escribir código que le permite crear y modificar datos de manera insegura. Para usar código inseguro, deberá configurar el compilador para permitir el código inseguro. Los punteros se pueden usar de esta manera. Al usar código inseguro, no se utilizan ciertas comprobaciones que están allí con código seguro, lo que hace que el código inseguro sea más difícil de escribir sin errores. Hay muy pocos lugares que puedan beneficiarse del código inseguro en C #. En Unity, el código inseguro no es compatible con todas las plataformas. Por lo general, usar referencias en lugar de punteros inseguros es suficiente cuando se trabaja con Unity.

Aquí hay un ejemplo ( fuente ) del uso de punteros de código inseguros en C # con Unity:

public static class Rope
{
    // C# function declaration to match C++
    [DllImport(SlingshotImport.c_libName)]
    static unsafe extern void UpdateRopeParticlesUnsafe(
        Vector3* oldNew,
        Vector3* curr,
        int numParticles);

    // C# wrapper function for Unity C# script
    static void UpdateRopeParticles(
        Vector3[] oldNew,
        Vector3[] curr,
        int numParticles)
    {
        unsafe
        {
            fixed (Vector3* oldNewPtr = oldNew)
            fixed (Vector3* currPtr = curr)
            {
                UpdateRopeParticlesUnsafe(oldNewPtr, currPtr, numParticles);
            }
        }
    }
}
Lasse
fuente
Me parece interesante que critique mi respuesta y use los mismos argumentos, menos otra información relevante, y solo incluya una breve discusión sobre el valor frente a los tipos de referencia. Al menos podría mencionar Boxing , optimizaciones JIT que a veces podrían eliminar la sobrecarga de la copia del tipo de valor, cómo evitar la inseguridad mediante la clasificación , o tal vez ese código inseguro no siempre es más rápido que seguro
Matthew Sanders
Lo siento si te sientes atacado u ofendido. No era mi intención. Critiqué su respuesta porque me parecía muy basada en opiniones en lugar de hechos. Proporcioné respuestas para las preguntas formuladas junto con un código de ejemplo. De su respuesta no pude entender las cosas que expliqué en mi respuesta, que sentí que eran más relevantes para la pregunta formulada. No veo cómo GC tiene algo que ver con "¿cómo uso punteros?" o no te vi mencionar cómo funcionan las referencias en C # ya que la pregunta parecía suponer que las variables funcionaban de la misma manera en C # y C ++.
Lasse
1
Sin preocupaciones. Gracias por tu disculpa Mencioné el GC, ya que debe tener en cuenta que pasar punteros a tipos administrados puede causar problemas si el GC mueve repentinamente el objeto. Asumí que el lector conocía el sistema de tipos C # y cómo se usan los tipos de referencia vs valor.
Matthew Sanders
Ustedes realmente hacen difícil aceptar una respuesta. Ambos me proporcionaron mucha información que era necesaria, así que los votaré a ambos y aceptaré el primero. No quiero decir nada con eso. Simplemente tengo dificultades para elegir y en cuanto a asustarme del "código inseguro" no se preocupe. De todos modos, nunca he sido el que se ha alejado de un desafío. Aunque ahora sé que trabajar con punteros no es práctico en lo que respecta al desarrollo multiplataforma. Quiero agradecerles a todos por su tiempo y opiniones. y lamento haber empezado la Segunda Guerra Mundial, no quería hacer eso.
Ryan Henry