8
votes

C ++ std :: paire, std :: vector & memcpy

est-il en sécurité à Membecopy myvect.Size () * Tailleof (FOO) octets de la MemieDrach du premier élément d'un xxx pré>

dans un tableau de p>

struct foo{
    T1 first;
    T2 second;
}


1 commentaires

std :: paire est une structure, la norme dit que le compilateur détermine la mise en page bien que la commande doit être maintenue, donc dans l'instance de STD :: paire Votre compilateur peut décider de placer un rembourrage de 3 octets après chaque char Pour un alignement optimal, non vous ne pouvez pas supposer la mise en page de mémoire contiguë - fin de l'histoire.


3 Réponses :


8
votes

Non, une classe contenant t1 et t2 n'est pas garantie la même disposition ou alignement que std :: paire , au moins en C ++ 98 (puisque std :: paire n'est pas un type de pod). L'histoire peut être différente en C ++ 0x.


9 commentaires

Mais STD :: paire n'est tout simplement pas de pod car il a un constructeur défini par l'utilisateur, non? Et cela ne devrait pas changer quelque chose sur la mise en page de la mémoire - ou le fait-il?


En C ++ 98, des implémentations sont autorisées à utiliser une disposition différente pour les types de pod non-POD par rapport aux types de POD. En C ++ 0X, si je me souviens bien, il existe une désignation spéciale pour les types qui ont des constructeurs, mais n'ont pas de classes de base, de fonctions virtuelles ou de membres non passionnés. Je ne me souviens pas de son nom, mais l'idée est que ces types sont suffisamment simples pour être Memcpy capable.


@Chris: la mise en page standard, mais une classe de mise en page standard n'est pas nécessairement sans danger pour la copie, cela signifie simplement (en vigueur) que le compilateur n'a inséré aucune mauvaise surprise. Une classe RAII contenant un pointeur à un objet alloué en tas, qu'elle libère de la destruction et des clones sur la mission, est la mise en page standard mais non pod, et ne devrait probablement pas être copiée avec MEMCY.


@Steve: Merci d'avoir expliqué! Beaucoup plus clair que tout ce que j'aurais pu écrire. :-)


Mat doit également noter qu'il est correct de faire le memcpy () si le myvect est de type std :: vecteur . Il pourrait être préférable aux puristes si std :: copy (copy (copy (COPY> est utilisé à la place de memcpy () .


@Michael: Seulement si struct foo est un type de pod. :-P (qui, pour cette question, signifie que t1 et t2 est également.)


Et c'est pourquoi STD :: Copy a intérêt à plus que des puristes - il copie des données non-POD.


@Chris: Droite - J'ai négligé ce détail (plutôt, j'ai supposé qu'ils étaient des types de pods - une hypothèse dangereuse). Cependant, std :: copie () fonctionnerait même s'il ne s'agit pas de POD (tant que le type prend en charge l'affectation). Donc, cela fait mal que mon fissure «puriste» - il devrait simplement être utilisé. Espérons que les optimisations empêchent le compilateur de cracher memcpy () Code équivalent si les types sont POD - Je vais devoir jeter un coup d'œil à une sortie ASM pour voir si cela se produit vraiment dans la pratique. En tout état de cause, la sortie serait probablement suffisamment bonne sauf si ce n'est pas (comment est-ce pour l'agitation des mains?).


En fait, certains compilateurs Créer un code pour std :: copy (copy (copy (copy (copy (copy (copy (copy (copy> c'est meilleur que std :: memcpy () - il est facile pour les spécialisations de Std :: Copie () Pour bénéficier des restrictions d'alignement de type. Par exemple. STD :: Copie Peut utiliser 64 bits Aligné Lecture / Écrit sans chèques antérieurs.



0
votes

En général, non. Sur certaines plates-formes / compilateurs / implémentations stl, cela pourrait être, mais ne le faites pas de toute façon. Vous deviez compter sur les détails de la mise en œuvre des deux paires <> et le vecteur <>.

J'ai moi-même commis le péché de compter sur le vecteur <> étant un tableau contigu. Pour cela, je me repentant profondément. Mais la paire <> ... Dites simplement non.


7 commentaires

En fait, le vecteur <> est garanti d'être un tableau contigu.


Il est presque admis que std :: vecteur est contigu (je pense que les futures versions de C ++ spécifieront ainsi), et que & VEC [0] doit être utilisable comme Un tableau de taille Vec.Size () . Mais, faire memcpy sur des types non-pod tels que std :: paire est risqué, oui.


Vous êtes pardonné, même en C ++ 03 ... std :: vecteur est requis pour utiliser le stockage contigu.


@Seva: à partir du projet de norme C ++ 03 23.2.5, "Les éléments d'un vecteur sont stockés contiguës, ce qui signifie que si v est un vecteur où T est un type autre que bool, puis il obéit le Identity & V [N] == & V [0] + n pour tous 0 <= N


@Seva: C ++ 03, 23.2.4.1: Les éléments d'un vecteur sont stockés contiguës, ce qui signifie que si v est un vecteur où T est un type autre que bool, puis il obéit l'identité & v [n ] == & V [0] + n pour tous 0 <= N


Quelques autres liens pour plus d'informations sur contigus std :: vecteur <> : Stackoverflow.com/questions/247738/... et Herbsutter.WordPress.com/2008/04/07 / ...


Merci a tous. Je ne rappelle pas exactement le timing du péché en question - peut-être que c'était avant l'année 03, peut-être après. Quoi qu'il en soit, je me sentais mal à l'aise à l'époque.



4
votes

La réponse à la question que vous n'avez pas posée est probablement std :: transformer code>: xxx pré>

ou std :: copie code> , mais donnez FOO un opérateur = code> prendre une paire comme paramètre. Cela suppose que vous pouvez ré-écrire FOO, bien que: P>

struct foo {
    T1 first;
    T2 second;
    foo &operator=(const std::pair<T1,T2> &p) {
        first = p.first;
        second = p.second;
        return *this;
    }
};

std::copy(myvect.begin(), myvect.end(), myarray);


2 commentaires

STD :: Transform () est quelque chose que je ne me souviens jamais. Déjà. Peut-être que maintenant que j'ai dit cela publiquement, ça va parfois me pousser dans ma tête.


STD :: Transform Est ce que vous obtenez au lieu de la carte et de ZipWith. Donc, peut-être que si chaque fois que vous oubliez de transformer, vous réécrivez la fonction pertinente de HASKELLL, vous vous en souviendrez. Si seulement pour éviter d'écrire Haskell.