Domanda

Ho visto una classe che è una classe definita in questo modo.

class StringChild : public StringBase
    {
public:
    //some non-virtual functions
    static StringChild* CreateMe(int size);
private:
    unsigned char iBuf[1];
    };

La funzione factory statica ha la seguente implementazione.

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Per quanto ho capito, questa funzione sta usando il posizionamento nuovo per estendere questa classe.

È sicuro solo perché c'è solo 1 membro ed è allocato nell'heap?

È stato utile?

Soluzione

È un vecchio trucco in C usato per aggirare la non disponibilità di matrici di lunghezza variabile nella pianura C. Sì, funziona anche in C ++ purché si utilizzino costrutti di allocatore adeguati (come allocare un mucchio di memoria grezza dimensione desiderata e quindi posizionamento rinnovando l'oggetto). È sicuro fino a quando non vaghi per la fine della memoria allocata, ma tende a confondere almeno alcuni debugger di memoria.

Una cosa che devi assolutamente accertare quando usi questa tecnica è che l'array a lunghezza variabile è l'ultimo elemento nel layout dell'oggetto, altrimenti passerai sopra altre variabili interne.

Sono comunque un po 'dubbioso sull'implementazione della funzione factory - suppongo che il parametro' size 'sia effettivamente la dimensione dell'array desiderata? Inoltre, non dimenticare che dovresti rilasciare la memoria sopra usando 'free' e non 'delete', anche se quest'ultimo potrebbe funzionare nella maggior parte dei casi.

A meno che non ci sia una ragione convincente per cui la memoria deve essere gestita in questo modo, sostituirò semplicemente l'array con uno std :: vector.

Altri suggerimenti

Questo dovrebbe essere OK per i POD a condizione che iBuf sia l'ultimo membro della struttura. I problemi con i non POD potrebbero essere ad es. il compilatore è libero di riordinare membri pubblici / privati ??/ protetti, le classi di base virtuali finiscono alla fine dell'oggetto IIUC più derivato, ecc.

La tua struttura non è POD (ha una classe base) quindi non la consiglierei.

Inoltre, se crei istanze come questa

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

Dovresti assicurarti che la memoria acquisita da malloc debba essere liberata gratuitamente, quindi elimina le tue istanze in questo modo:

obj->~StringChild();
free(obj);

Forse ti piacerebbe usare :: operator new () per allocazione

A rigor di termini, poiché StringChild è derivato da StringBase non è sicuro. Lo standard C ++ non specifica il layout per gli oggetti secondari della classe base. Clausola 10, paragrafo 3:

  

L'ordine in cui gli oggetti secondari della classe base sono allocati nell'oggetto più derivato (1.8) non è specificato.

Se StringChild fosse una struttura POD, una tale tecnica sarebbe sicura.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top