2010-01-05 8 views
7

est sans danger pour memcopy myvect.size() * sizeof (foo) octets à partir du memoryadress du premier élément d'unC++ std :: pair, std :: vecteur & memcopy

std::vector<std::pair<T1, T2> > myvect 

dans un tableau de

struct foo{ 
    T1 first; 
    T2 second; 
} 

si le tableau est alloué avec le même nombre d'éléments que la taille du vecteur?

grâce

+1

std :: paire est un struct, la norme indique que le compilateur détermine la mise en page doit être maintenue si l'ordre, donc dans l'instance de std :: paire votre compilateur peut décider de placer un remplissage de 3 octets après chaque caractère pour un alignement optimal, donc non vous ne pouvez pas supposer la disposition de la mémoire contiguë - fin de l'histoire. –

Répondre

8

Non, une classe contenant T1 et T2 ne sont pas garanties la même disposition ou l'alignement comme std::pair<T1, T2>, au moins en 98 (depuis std::pair est pas un type de POD) C++. L'histoire peut être différente en C++ 0x.

+0

mais std :: pair n'est juste pas un 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? – Mat

+0

En C++ 98, les implémentations sont autorisées à utiliser une mise en page différente pour les types non-POD par rapport aux types POD. En C++ 0x, si je me souviens bien, il existe une désignation spéciale pour les types qui ont des constructeurs, mais qui n'ont pas de classes de base, de fonctions virtuelles ou de membres non triviaux. Je ne peux pas me souvenir de son nom, mais l'idée est que de tels types sont assez simples pour être «memcpy». –

+1

@Chris: standard-layout, mais une classe standard-layout n'est pas * nécessairement * sûre pour la copie, cela signifie juste (en effet) que le compilateur n'a pas inséré de mauvaises surprises. Une classe RAII contenant un pointeur vers un objet alloué par tas, qu'elle libère lors de la destruction et des clones lors de l'affectation, est une mise en page standard mais pas un POD, et ne devrait probablement pas être copiée avec memcpy. –

0

En général, pas. Sur certaines plates-formes/compilateurs/implémentations STL, il pourrait être, mais ne le faites pas de toute façon. Vous comptez sur les détails d'implémentation de la paire <> et du vecteur <>.

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

+5

En fait, le vecteur <> EST un ensemble contigu. –

+0

@Fred: veuillez citer? –

+0

Il est pratiquement admis que 'std :: vector ' est contigu (je pense que les futures versions de C++ le spécifieront), et que '& vec [0]' devrait être utilisable comme un tableau de taille 'vec.size()' . Mais, faire 'memcpy' sur des types non-POD comme' std :: pair' est risqué, oui. –

4

La réponse à la question que vous n'avez pas demandé est probablement std::transform:

struct pairToFoo { 
    // optionally this can be a function template. 
    // template<typename T1, typename T2> 
    foo operator()(const std::pair<T1,T2> &p) const { 
     foo f = {p.first, p.second}; 
     return f; 
    } 
}; 

std::transform(myvect.begin(), myvect.end(), myarray, pairToFoo()); 

Ou std::copy, mais donner foo un operator= prendre une paire comme paramètre. Cela suppose que vous pouvez ré-écrire foo, si:

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); 
+0

'std :: transform()' est quelque chose dont je ne me souviens jamais. Déjà. Peut-être que maintenant que je l'ai dit publiquement, ça me viendra parfois à l'esprit. –

+1

'std :: transform' est ce que vous obtenez à la place de map et zipWith. Alors peut-être que si à chaque fois que vous oubliez de transformer, vous réécrivez la fonction pertinente dans Haskell, alors vous vous en souviendrez. Si seulement pour éviter d'avoir à écrire Haskell. –

Questions connexes