7
votes

Comment faire l'équivalent du memset (ceci, ...) sans encombrer le VTBL?

Je sais que le memset est froncé sur pour Classe Code> Initialisation. Par exemple, quelque chose comme ce qui suit:

class X { public: 
X() { memset( this, 0, sizeof(*this) ) ; }
...
} ;


9 commentaires

En règle générale, vous prenez l'adresse du premier champ et clarifiez à partir de là. Nul doute que cela viole une certaine règle, mais cela a toujours travaillé pour moi.


L'autre option consiste à écrire votre propre routine Alloc pour la classe, de sorte que vous pouvez assurer que l'espace est effacé, mais IIRC existe des restrictions autour de cela.


Vous ne voulez pas dire memset (ceci, 0, taille de * this) ? (Et oui, cela clouerait également le VTBL.)


@Hotlicks, il semble que le problème de cette approche connaisse la bonne taille. la taille de (ceci) ne sera probablement pas la même que la taille de ().


Vous pouvez prendre l'adresse du champ et soustraire ceci à partir de celui-ci, puis soustrayez le reste de la taille de l'objet.


@Hot lèche ce que vous suggère de fonctionner correctement si vous êtes uniquement sur un seul compilateur et utilisez soigneusement les règles de mise en page de la mémoire de ce compilateur. Par exemple, si votre projet n'est jamais compilé avec MSVC, cela peut fonctionner. Mais, différents compilateurs ont des règles différentes pour les vtables, etc. (ils pourraient même utiliser quelque chose d'autre qu'un fourble, théoriquement). Donc, cela pourrait facilement se transformer en imbécile de Scary FI-DEFS si vous devez utiliser ce type de truc sur plusieurs compilateurs.


Qu'est-ce qui ne va pas avec la rédaction d'un constructeur qui initialise explicitement les membres?


Ce n'est pas seulement à propos de la machine à guichets, vous pouvez également avoir des membres de la mise en page non standard, que memset se gâcherait également. Faites un choix: écrivez en C (et Gut les portions C ++) ou écrivez en C ++ (et utilisez C ++ idiomes). Mélanger ces deux choses est dangereux et il est probablement plus facile (et supérieur) de commencer à prendre le temps de réparer ces classes une à la fois pour leur donner des constructeurs appropriés, sans les singeries C.


@WeirdlyDycheezy - comme je l'ai dit, cela viole sans doute plusieurs règles, mais cela a toujours travaillé pour moi.


7 Réponses :


1
votes

Vous pouvez toujours ajouter des constructeurs à ces structures intégrées, de sorte qu'elles se déflèrent pour ainsi dire.


1 commentaires

La question est vraiment sur ce qu'il faut mettre dans le constructeur (ce n'est pas, disons, 100 déclarations d'affectation).



1
votes

Ceci est hideux, mais vous pourrait em> surcharger Opérateur neuf / Supprimer CODE> pour ces objets (ou dans une classe de base commune) et que la mise en œuvre fournisse zéro tampons. Quelque chose comme ceci:

class HideousBaseClass
{
public:
    void* operator new( size_t nSize )
    {
        void* p = malloc( nSize );
        memset( p, 0, nSize );
        return p;
    }
    void operator delete( void* p )
    {
        if( p )
            free( p );
    }
};


0 commentaires

4
votes

Pour chaque classe où vous trouvez un memset appelez, ajoutez une fonction MEMSET MEMSET Ignore les arguments du pointeur et de la taille et fait des affectations à tous les membres de données.

éditer: En fait, il ne devrait pas ignorer le pointeur, il devrait le comparer à ce . Sur une correspondance, faites la bonne chose pour l'objet, sur une inadéquation, Reroute à la fonction globale.


1 commentaires

Oui, il y a du mérite à cela. Plus facile à rappeler de la garder mise à jour que de gérer des listes dans 5 constructeurs différents.



1
votes

Essayez ceci: xxx pré>

Ceci a mis à zéro votre objet - peu importe ce qu'il s'agit de POD ou non. P>

mais ne fais pas cela: P>

  struct AData { ... all A members };
  class  A { 
   public: 
      A() { reset(data); } 
   private: 
      AData data; 
   };


4 commentaires

Est-ce ce que la valeur de boost_initialisé: boost.org/doc/libs /1_38_0/libs/uttility/value_init.init.htm fait?


@Peeterjoot plus ou moins ça fait. En fait, il le fait de manière plus compliquée, cette bibliothèque de Boost affirme qu'en raison de certains problèmes de compilateur et que la manière présentée dans ma réponse n'est pas toujours la manière la plus efficace pour les types de non-POD, il utilise la variable constante statique à des fins. Toutefois, si vous recherchez un remplacement du memset - ma manière «simplifiée» devrait suffire.


T = T (); Cela ne sera pas zéro de l'objet, il le remplacera par une valeur construite par défaut. Si le constructeur par défaut n'initialise pas un membre, ce membre restera toujours ininitialisé. Si cela initialise quelque chose à la non-zéro, il sera également laissé à cette valeur. Réinitialisation à Par défaut au lieu de Tous les zéros peut être une bonne chose, mais ils ne sont pas les mêmes que vous le suggérez.


@Shahbaz - Il sera zéro objet en C ++ Sens: pour les types de pod - Tous les numéros à Zeros, Bool à Faux, les pointeurs à NULLS. Pour NON-POD (le cas que vous avez décrit) L'objet construit par défaut sera utilisé - de sorte que quelqu'un écrit le constructeur par défaut de mauvaise manière - alors aucun moyen - cela échouera. Mais voyez à l'exemple que j'ai fourni - l'ADATA est défini comme un agrégat simple, de sorte que ses membres sont une pod ou une non-POD avec un constructeur par défaut valide - il fonctionnera toujours.



0
votes

Vous pouvez utiliser le pointeur arithmétique pour trouver la plage d'octets que vous souhaitez zéro sortir: xxx

(modifier: j'ai utilisé à l'origine offsetof () pour cela, Mais un commentaire a souligné que cela ne serait censé fonctionner que sur des gousses, puis j'ai réalisé que vous pouvez simplement utiliser directement les adresses membres.)


0 commentaires

0
votes

La meilleure solution que je puisse trouver est de créer une structure séparée où vous mettrez les membres qui doivent être memsettés à zéro. Je ne sais pas si cette conception vous convient.

Cette structure n'a pas de table à table et ne s'étend rien. Ce sera juste un morceau de données. De cette façon, le memseting La struct est sûre.

J'ai fait un exemple: xxx


0 commentaires

1
votes

Tirer parti du fait qu'une instance statique est initialisée à zéro: https://ideone.com/gefkg0 xxx pré>

Cependant, ce qui précède causera le constructeur (de la classe templatumée) à appeler une seconde fois. p>

pour une solution qui ne provoque aucun appel CTOR Ceci peut être utilisé à la place: https://ideone.com/qto6ka p> xxx pré>

... et si vous utilisez c ++ 11 à l'envers Suite peut être utilisé: https://ideone.com/s1ae8g p>

template <class T>
struct clearable
{
    void clear()
    {
        *((T*)this) = {};
    };
};


0 commentaires