Domanda

Esiste un metodo migliore per stabilire l'offset del membro di dati di un oggetto di posizionale il seguente?

class object
{
  int a;
  char b;
  int c;
};

object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
È stato utile?

Soluzione

In questo caso, la classe è POD, in modo da poter utilizzare la macro offsetof da <cstddef>.

In pratica, nella maggior parte delle implementazioni, per la maggior parte delle classi, è possibile utilizzare lo stesso trucco che offsetof tipicamente utilizza:

int offset = &(((object *)0)->c) - (object *)0;

Non c'è bisogno di creare effettivamente un oggetto, anche se potrebbe essere necessario combattere alcuni avvisi del compilatore perché questo non è garantito per funzionare.

Attenzione, inoltre, che se la classe ha qualche ereditarietà multipla, poi per (almeno) tutti, ma una base, (void*)(base*)some_object != (void*)(derived*)some_object. Quindi bisogna stare attenti a quello che si applica l'offset. Finché si calcola e applica rispetto a un puntatore alla classe che definisce in realtà il campo (cioè, non cercare di capire l'offset di un campo di classe di base da un puntatore classe derivata) sarà quasi certamente essere bene. Non ci sono garanzie circa il layout oggetto, ma la maggior parte delle implementazioni farlo nel modo più ovvio.

Tecnicamente per qualsiasi classe di non-POD, non ha senso parlare di "l'offset" di un campo dal puntatore base. La differenza tra i puntatori non è richiesto di essere lo stesso per tutti gli oggetti di quella classe.

Altri suggerimenti

Non c'è bisogno per creare effettivamente un oggetto:

(size_t)&(((object*)0)->c)

Cioè, l'indirizzo di un elemento in un oggetto all'indirizzo zero l'offset del membro nell'oggetto.

Naturalmente, sarà necessario accedere al membro, quindi è necessario o renderlo un struct o aggiungere un modificatore di accesso public:.

Questo è il modo offsetof è implementato, almeno per la maggior parte dei compilatori.

Invece di un puntatore.
È possibile utilizzare un puntatore a un membro.

class X;
typedef int X::*    PtrToMemberInt;  // Declare a pointer to member.

class X
{
    int a;
    char b;
    float c;

    public:
    static PtrToMemberInt   getAPtr()
    {
        return &X::a;
    }

    int d;
};

int main()
{
    // For private members you need to use a public method to get the address.
    PtrToMemberInt aPtr = X::getAPtr();

    // For public members you can take the address directly;
    PtrToMemberInt dPtr = &X::d;


    // Use the pointer like this:
    X   a;
    a.*aPtr = 5;
    a.*dPtr = 6;
}

Per aggiungere a Martins risposta, come indicato in "Progettazione e evoluzione del C ++" di Stroustrup (sezione [13.11]):

  

puntatori a membri di dati hanno dimostrato una   modo utile per esprimere il layout   una classe C ++ in un'implementazione   [Hübel 1992]

Sandeep è stato così gentile da convertire la carta originale e renderlo disponibile su http://sandeep.files.wordpress.com/2008/07/ps.pdf

Si noti che l'attuazione descritta precedette C ++ RTTI, ma di tanto in tanto usano ancora la roba puntatore-a-membro.

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