memcpy und alignment



  • Hallo,

    ich habe folgenden (nicht meinen) code vor mir:

    struct blabla
    {
      int    a;   
      int    b;   
    
      double c;   
      double d;
    
      anderes_struct e;
      anderes_struct f;
    
      blabla(){memset(this,0,sizeof(blabla));};
      blabla(const blabla&other){memcpy(this,&other,sizeof(blabla));};
      blabla& operator=(const blabla&other){memcpy(this,&other,sizeof(blabla));return *this;};
    }
    

    Ist die Verwendung von memcpy/memset für structs bestehen nur aus POD okay? Mir persönlich fällt da memory alignment im Release Modus als Mögliches Problem auf.

    Wie sieht es aus wie in diesem Fall, wenn auch andere structs, oder Klassen die nicht nur aus POD bestehen ein Teil der Klasse sind?



  • Nur als Anmerkung: Structs/Klassen mit einem Custom-Default-Constructor sind keine PODs mehr.


  • Mod

    Der implizit deklarierte Kopierkonstruktor und Zuweisungsoperator vom Compiler kopiert alles schon für dich, und wenn man alles ausnullen will dann muss man auch nicht memset verwenden, sondern kann die Klasse mit {} initialisieren - wenn diese ein POD wäre (was hier nicht der Fall ist), dann würde dieser Initializer das Objekt zero-initializen, was soviel heißt wie: Padding ausnullen, alle Skalare auf Null setzen, und andere Member wiederum zero-initializen.

    anderes_struct

    Was ist das für eine Struktur? Ein POD-Typ?

    Du brauchst ja nach einer Kopie nicht auch das gleiche Padding, oder? 😉

    theta schrieb:

    Nur als Anmerkung: Structs/Klassen mit einem Custom-Default-Constructor sind keine PODs mehr.

    👍
    Standardlayout hat es allerdings.



  • Arcoth schrieb:

    Was ist das für eine Struktur? Ein POD-Typ?

    struct anderes_struct
    {
        int row,col;
        unsigned char value;
    
    	anderes_struct():row(0),col(0),value(0){};
    	anderes_struct(int r,int c):row(r),col(c),value(0){};
    	anderes_struct(int r,int c,unsigned char v):row(r),col(c),value(v){};
    	anderes_struct(unsigned int r,unsigned int c):row((int)r),col((int)c),value(0){};
    	anderes_struct(unsigned int r,unsigned int c,unsigned char v):row((int)r),col((int)c),value(v){};
    	anderes_struct(double r,double c,unsigned char v);
    	anderes_struct(double r,double c);
    	anderes_struct( const anderes_struct &other);
    	anderes_struct(const anderes_struct2 &other);
    	anderes_struct& operator=(const anderes_struct& other);
    	anderes_struct& operator=(const anderes_struct2& other);
    	anderes_struct& operator+=(const anderes_struct&other);
    	anderes_struct& operator-=(const anderes_struct&other);
    	anderes_struct   operator+ (const anderes_struct&other);
    	anderes_struct   operator- (const anderes_struct&other);
    	anderes_struct2  operator+ (const anderes_struct2&other);
    	anderes_struct2  operator- (const anderes_struct2&other);
    
    	anderes_struct operator* (int skalar);
    	anderes_struct operator* (double skalar);
    	anderes_struct operator/ (int skalar);
    	anderes_struct operator/ (double skalar);
    	anderes_struct& operator/=(int skalar);
    	anderes_struct& operator/=(double skalar);
    };
    

  • Mod

    Übrigens: §3.9/2 und /3 gelten auch nur für trivial kopierbare Typen. Deine Klasse ist offensichtlich nicht trivial kopierbar, also muss *this nach der Kopie in Zeilen 12 und 13 nicht denselben Wert haben wie other .
    Ob das UB ist, kann ich aber nicht mit Sicherheit sagen (sieht irgendwie nicht danach aus, halt nur danach, dass das Ergebnis nicht festgelegt ist), das weiß bestimmt camper.

    anderes_struct ist nach deinem Code-Schnipsel kein POD, und auch nicht trivial kopierbar.



  • Arcoth schrieb:

    Übrigens: §3.9/2 und /3 gelten auch nur für trivial kopierbare Typen.

    Was ist mit " §3.9/2 und /3" gemeint? Wäre dir für einen Link dankbar.


  • Mod

    dasdsad schrieb:

    Arcoth schrieb:

    Übrigens: §3.9/2 und /3 gelten auch nur für trivial kopierbare Typen.

    Was ist mit " §3.9/2 und /3" gemeint? Wäre dir für einen Link dankbar.

    Das sind Standardparagraphen:

    §3.9/2 schrieb:

    For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char . If the content of the array of char or unsigned char is copied back into the
    object, the object shall subsequently hold its original value.

    #define N sizeof(T)
    char buf[N];
    T obj;                        // obj initialized to its original value
    std::memcpy(buf, &obj, N);    // between these two calls to std::memcpy,
                                  // obj might be modified
    std::memcpy(&obj, buf, N);    // at this point, each subobject of obj of scalar type holds its original value
    

    §3.9/3 schrieb:

    For any trivially copyable type T , if two pointers to T point to distinct T objects obj1 and obj2 , where
    neither obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making up obj1 are copied
    into obj2 , obj2 shall subsequently hold the same value as obj1 .

    T* t1p;
    T* t2p;
    // provided that t2p points to an initialized object ...
    std::memcpy(t1p, t2p, sizeof(T));
    // at this point, every subobject of trivially copyable type in *t1p contains
    // the same value as the corresponding subobject in *t2p
    

Anmelden zum Antworten