0

Voici mon code:Comment mettre en œuvre constructeur de copie en toute sécurité pour la classe qui a le placement interne nouveau (avec std :: string)

struct RS_Token 
{ 
    char id; 
    char cleanup; 
    unsigned char array[sizeof (std::string) > sizeof (double) ? sizeof (std::string) : sizeof (double)]; 

    RS_Token(int a) : 
     id(a), 
     cleanup(0) 
    { 
    } 
    RS_Token(int a, const char* pstr) : // identifier or text 
     id(a), 
     cleanup(1) 
    { 
     new (array) std::basic_string<unsigned char>((unsigned char*)pstr); 
    } 
    RS_Token(int a, int b) : // integer 
     id(a), 
     cleanup(0) 
    { 
     new (array) int(b); 
    } 
    RS_Token(int a, double b) : // float (double) 
     id(a), 
     cleanup(0) 
    { 
     new (array) double(b); 
    } 

    ~RS_Token() 
    { 
     if (cleanup) 
     { 
      std::basic_string<unsigned char>* p = reinterpret_cast<std::basic_string<unsigned char>*>(array); 

      p->~basic_string(); 
     } 
    } 
}; 

Toutes les suggestions sur la façon d'ajouter un constructeur de copie qui gère correctement le cas où un std :: string a été attribué en interne, serait apprécié.

+4

Ce qui est mal à faire à part 'std :: string' et les variables' double'? Le code que vous avez aura [sérieux problèmes d'alignement] (http://www.gotw.ca/gotw/028.htm) entre autres choses. Et si vous en faites des variables membres distinctes, le constructeur de copie généré par le compilateur fera le bon choix pour vous. –

+0

Placement-nouveau prend généralement un argument 'void *', donc vous pouvez vous épargner ces moulages fastidieux. –

+0

Probablement 'boost :: variant ' prendrait soin de ces choses. – visitor

Répondre

1

Je ne suis pas sûr que ce que vous faites est du tout une bonne conception, mais pour répondre à votre question de placement nouvelle sur: Vous fournissez les arguments du constructeur comme dans toute autre expression new:

construire une nouvelle chaîne:

typedef std::basic_string<unsigned char> ustring; 

RS_Token(const char* pstr) 
{ 
    void * p = static_cast<void*>(array); 
    new (p) ustring(pstr, pstr + std::strlen(pstr)); 
} 

Copy-construction:

RS_Token(const RS_Token & other) 
{ 
    void * p = static_cast<void*>(array); 
    new (p) ustring(*reinterpret_cast<const ustring *>(other.array)); 
} 

Assign:

RS_Token & operator=(const RS_Token & other) 
{ 
    ustring & s = *reinterpret_cast<ustring *>(array); 
    s = *reinterpret_cast<const ustring *>(other.array); 
    return this; 
} 
+0

Ce constructeur de copie ne fonctionne que si l'autre contient une chaîne, et l'opérateur d'assignation suppose que _both_ est déjà une chaîne. Ils devront être un peu plus compliqués que ça. –

+0

@Moo: Ah, oui, une bonne partie de la logique de la variante doit être ajoutée ici. Mais la réponse concerne la gestion de la construction du placement, donc j'espère que le PO pourra l'intégrer dans son code de classe. –

+0

hein, c'est vrai. Vous avez toutes les parties difficiles. Le reste devrait être assez évident. –

Questions connexes