Puntatori in C # Unity


8

Ehi, ho appena imparato a conoscere i puntatori di recente e mi chiedo come posso usarli in c # (ho appena imparato a conoscerli in c ++) in unità. Ho alcune domande però.

  1. I puntatori utilizzano una programmazione di basso livello per trovare posizioni di valori diversi sul computer, quindi ciò significa che è possibile accedere al valore di una variabile da qualsiasi script?
  2. In tal caso, come posso semplicemente fare riferimento a una posizione di una variabile con solo il suo codice di posizione?
  3. Ci sono differenze riconoscibili tra i puntatori in C # e C ++ che dovrei conoscere?
  4. Come posso usare i puntatori con i tipi di variabili in Unity (Vector3s, Transforms, GameObjects, ecc ...)?

Ci sono così tante altre domande che probabilmente dovrei e vorrei porle se hai ulteriori informazioni o fonti.

Risposte:


6

In generale per C # e in particolare per Unity, lo sconsiglio ... ma se lo volessi davvero, o avessi delle buone ragioni, potresti farlo.

In C # dovresti familiarizzare con il cosiddetto codice non sicuro . Ancora spaventato?

In Unity dovresti abilitare la modalità di compilazione non sicura in modo da non poter utilizzare il web player se lo hai pianificato. Puoi leggere di più qui o qui .

Quindi fondamentalmente C # è stato progettato con un Garbage Collector come molti linguaggi di scripting. L'idea generale è di cercare di astrarre il concetto di gestione della memoria per semplificare lo sviluppo. Puoi comunque finire con perdite di risorse se non annulli i tuoi oggetti. Onestamente non sono un grande sostenitore dei GC e preferirei invece i metodi RAII , ma questo è il mondo in cui viviamo.

La maggior parte degli sviluppatori C ++, tuttavia, concorderebbe anche sul fatto che non si dovrebbero usare direttamente i puntatori e preferirebbe usare un tipo progettato RAII, ovvero i puntatori intelligenti . Se ti trovi in ​​terra C, allora probabilmente i puntatori sono una seconda natura per te, ma anche in questo caso ti aiuta ad astrarli in una certa misura.

Se li usi in C #, tieni presente che esiste un potenziale molto reale che potresti aggiungere vulnerabilità di sicurezza o bug davvero difficili da rintracciare. Dovrai inoltre tenere presente che devi fare attenzione a non fare riferimento a oggetti che possono essere spostati dal GC. Si noti l'uso della dichiarazione fisso qui .

Puoi anche usare i puntatori in Unity scrivendo un plugin nativo . Questo di nuovo escluderà le build di webplayer, ma la nuova funzionalità HTML5 funziona in base a emscripten, quindi se hai pianificato di usarlo probabilmente potresti farlo se stai attento. I plug-in nativi consentono di estendere Unity in base alla piattaforma. Ho scritto un plugin nativo per comunicare con alcuni microcontrollori tramite una connessione seriale, ad esempio.

Quindi per riassumere dovresti sicuramente chiederti perché voglio usare i puntatori in C # in Unity. Se vuoi solo farlo per divertimento ... Mettiti al tappeto.

Modifica: mi dispiace se avevo offeso qualcuno perché so che i miei pensieri su GC non sono dell'opinione popolare in questo momento.

Se leggi davvero la mia risposta noterai che non chiamo C # un linguaggio di scripting. Lo paragono a "molti linguaggi di scripting", tuttavia, nel contesto di Unity, è molto utilizzato come linguaggio di scripting. È un po 'un DSL per Unity, se vuoi. Spesso lo vedrai anche chiamato Unity Script in questo contesto (questo è principalmente in riferimento all'alternativa Javascript di Unity a C #). Se metti LLVM nella tua pipeline puoi semplicemente compilarlo direttamente nel codice nativo per la piattaforma ... come lo chiameresti? Quindi davvero non volevo spaccare i capelli qui.

Molti grandi riferimenti all'ingegneria del software sono pieni di opinioni:

Efficace C ++ , C ++ più efficace , Domande frequenti su C ++ , C # efficace , Design moderno C ++ , Modelli di progettazione ... E innumerevoli altri. Non credo che ciò renda gli argomenti meno credibili se seguiti da una spiegazione ponderata.

Non stavo davvero dicendo "Non usare mai i puntatori !!" . In effetti, li uso ancora nudi in occasione. Ho detto "in generale" come in "preferisco usare il codice sicuro al codice non sicuro in C #". Ci sono situazioni in cui può essere utile, e questa è una delle funzionalità davvero potenti di C # per scegliere i tuoi strumenti. C # ti consente persino di avere una certa trasparenza nel processo GC, linguaggi come Dart no e possono portare a perdite di risorse molto facilmente. Sicuramente se sei l'unico sviluppatore di un piccolo progetto, probabilmente non è un problema. Se fai parte di un team di 10+ persone con centinaia di migliaia di righe di codice, può diventare complicato.

Volevo semplicemente che il lettore prestasse attenzione quando usa puntatori nudi. È come dire stare molto attenti quando si lavora con l'elettricità di rete. Non sto dicendo di non essere un elettricista, solo che se fai la mossa sbagliata e non la tratti con rispetto sei morto.

Mi piace l'esempio dato da Lasse in cui la performance potrebbe aver dettato la necessità.


1
C # non è un linguaggio di scripting, ma può essere usato per questo. Anche Java ha un GC e non è nemmeno un linguaggio di scripting. Rispondere con la propria opinione su ciò che è meglio in generale, non è la risposta obiettiva che stiamo cercando su questo sito. Per uno scopo specifico qualcosa come un codice non sicuro e puntatori possono essere davvero efficienti.
Lasse,

1
Non capisco perché questa risposta sia stata sottoposta a votazione negativa: è molto istruttiva e mostra molta ricerca / conoscenza e collegamenti a ulteriori letture. Soprattutto a @Lasse qual è il linguaggio di scripting? Ovviamente sarebbe più preciso dire "linguaggio usato per lo scripting nell'unità", ma non vedo molte ragioni per ridimensionare perché Matthew ha omesso 7 parole ovvie e ha usato un termine (sopra) semplificato.
Wondra,

@wondra Ho donato votato perché la risposta non sta rendendo ovvio che ci sono posti in cui i puntatori possono benissimo essere usati in C #. Tutto dipende dallo scopo e dalla piattaforma di destinazione. In effetti la risposta sta cercando di spaventare tutti dall'uso dei puntatori.
Lasse,

1
@wondra Questa risposta non risponde alla domanda. Tutto ciò che fa è dire di non usare i puntatori. Questa sezione dei commenti non è il posto giusto per discuterne. Puoi unirti alla chat se pensi di avere più argomenti.
Lasse,

1
@Lasse non può convincere te e non è la mia lotta, ma vedendo la tua risposta - hai scritto esattamente lo stesso di questa risposta (che è stata pubblicata prima), inoltre hai anche incluso solo un sottoinsieme (= meno informazioni) sull'argomento come ha fatto questa risposta.
Wondra,

6

C # usa riferimenti per passare intorno a oggetti che non sono tipi di valore . Ciò significa che di solito tutto viene passato per riferimento. Se si desidera passare un tipo di valore per riferimento, è possibile utilizzare la parola chiave ref . La differenza tra un tipo di riferimento e un tipo di valore è che a seconda della dimensione del tipo di valore, in genere richiede più memoria copiata quando viene passata a una funzione. Un riferimento è solo 32 bit o 64 bit , oppure 4 byte o 8 byte. Puoi ottenere più prestazioni dal tuo codice in loop molto stretti se usi riferimenti invece di copiare tutti i dati contenuti nelle variabili tipizzate dal valore, supponendo che siano maggiori di 4 o 8 byte.

Ad esempio, su Unity qualsiasi oggetto MonoBehaviour (class) è un tipo di riferimento e qualsiasi oggetto Vector3 (struct) è un tipo Value.

Esistono anche blocchi di codice non sicuri che ti permetteranno di digitare il codice che ti consente di creare e modificare i dati in modo non sicuro. Per utilizzare un codice non sicuro dovrai impostare il compilatore per consentire il codice non sicuro. I puntatori possono essere utilizzati in questo modo. Usando un codice non sicuro alcuni controlli non vengono utilizzati che sono lì con un codice sicuro, il che rende più difficile scrivere un codice non sicuro senza errori. Esistono pochissimi luoghi che possono trarre vantaggio dal codice non sicuro su C #. Su Unity il codice non sicuro non è supportato su tutte le piattaforme. In genere, quando si lavora con Unity è sufficiente utilizzare riferimenti anziché puntatori non sicuri.

Ecco un esempio ( sorgente ) di utilizzo di puntatori di codice non sicuri in 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);
            }
        }
    }
}

Trovo interessante che tu critichi la mia risposta e usi gli stessi argomenti, meno altre informazioni rilevanti, e includa solo una breve discussione del valore rispetto ai tipi di riferimento. Potresti almeno menzionare Boxing , ottimizzazioni JIT che a volte potrebbero rimuovere il tipo di valore overhead della copia, come evitare il marshalling non sicuro o forse che il codice non sicuro non è sempre più veloce che sicuro
Matthew Sanders,

Mi dispiace se ti senti attaccato o offeso. Non era mia intenzione. Ho criticato la tua risposta per questo mi è sembrato molto basato sull'opinione invece che sulla base dei fatti. Ho fornito le risposte alle domande poste insieme ad alcuni codici di esempio. Dalla tua risposta non sono stato in grado di comprendere le cose che ho spiegato nella mia risposta, che ho ritenuto più pertinenti alla domanda posta. Non vedo come GC abbia a che fare con "come posso usare i puntatori?" o non ti ho visto menzionare come funzionano i riferimenti su C # poiché la domanda sembrava assumere che le variabili funzionassero allo stesso modo in C # e C ++.
Lasse,

1
Nessun problema. Grazie per le tue scuse. Ho menzionato il GC poiché è necessario essere consapevoli del fatto che il passaggio di puntatori ai tipi gestiti può causare problemi se il GC sposta improvvisamente l'oggetto. Supponevo che il lettore fosse a conoscenza del sistema di tipi C # e di come vengono usati i tipi di riferimento rispetto a quelli di valore.
Matthew Sanders,

Ragazzi, rendete davvero difficile accettare una risposta. Entrambi mi avete fornito molte informazioni necessarie, quindi voterò entrambi e accetterò quello che è arrivato per primo. Non intendo nulla per questo. Ho appena avuto difficoltà a scegliere e per quanto riguarda spaventarmi da "codice non sicuro" non ti preoccupare. Non sono mai stato io a ritirarmi da una sfida comunque. Anche se ora so che lavorare con i puntatori è poco pratico in quanto riguarda lo sviluppo multipiattaforma. Voglio ringraziare tutti per il tempo e le opinioni. e mi dispiace che ho iniziato la seconda guerra mondiale non meen per farlo.
Ryan Henry,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.