2010-01-05 18 views
7

Es seguro memcopy myvect.size() * sizeof (foo) bytes desde el memoryadress del primer elemento de unC++ std :: pair, std :: vector y memcopy

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

en una matriz de

struct foo{ 
    T1 first; 
    T2 second; 
} 

si la matriz tiene asignada la misma cantidad de elementos que el tamaño del vector?

gracias

+1

std :: pair es una estructura, la norma dice que el compilador determina la disposición de que el orden debe ser mantenido, por lo que en el caso de std :: par su compilador puede decidir colocar relleno de 3 bytes después de cada char para una alineación óptima, por lo que no puede asumir el diseño de memoria contigua - final de la historia. –

Respuesta

8

No, una clase que contenga T1 y T2 no se garantiza la misma disposición o alineación como std::pair<T1, T2>, al menos en C++ 98 (desde std::pair no es un tipo POD). La historia puede ser diferente en C++ 0x.

+0

pero std :: pair simplemente no es POD porque tiene un constructor definido por el usuario, ¿no? y esto no debería cambiar algo en el diseño de la memoria, ¿o no? – Mat

+0

En C++ 98, las implementaciones pueden utilizar un diseño diferente para los tipos que no son POD en comparación con los tipos POD. En C++ 0x, si mal no recuerdo, hay una designación especial para los tipos que tienen constructores, pero no tienen clases base, funciones virtuales o miembros no triviales. No recuerdo su nombre, pero la idea es que esos tipos sean lo suficientemente simples para ser 'memcpy'able. –

+1

@Chris: diseño estándar, pero una clase de diseño estándar no es * necesariamente * segura para copiar, solo significa (en efecto) que el compilador no ha insertado ninguna sorpresa desagradable. Una clase RAII que contiene un puntero a un objeto asignado en el montón, que libera en la destrucción y los clones en la asignación, es de diseño estándar pero no POD, y probablemente no debería copiarse con memcpy. –

0

En general, no. En algunas plataformas/compiladores/implementaciones de STL podría ser, pero no lo haga de todos modos. Confiaría en los detalles de implementación tanto del par <> como del vector <>.

Yo mismo he cometido el error de confiar en el vector <> que es una matriz contigua. Por eso, me arrepiento profundamente. Pero el par <> ... Solo diga que no.

+5

En realidad, se garantiza que el vector <> IS es una matriz contigua. –

+0

@Fred: cite por favor? –

+0

Se acepta que 'std :: vector ' es contiguo (creo que las versiones futuras de C++ lo especificarán), y que '& vec [0]' debería usarse como una matriz de tamaño 'vec.size()' . Pero hacer 'memcpy' en tipos que no sean POD como' std :: pair' es arriesgado, sí. –

4

La respuesta a la pregunta que no pidió es probablemente 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()); 

O std::copy, sino dar un foo operator= tomar un par como parámetro. Esto supone que se puede volver a escribir foo, sin embargo:

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()' es algo que nunca recuerdo. Nunca. Tal vez ahora que lo he dicho públicamente, a veces me saltará en la cabeza. –

+1

'std :: transform' es lo que obtienes en lugar de map and zipWith. Entonces, tal vez, si cada vez que te olvidas de la transformación, vuelves a escribir la función relevante en Haskell, entonces lo recordarás. Si solo para evitar tener que escribir Haskell. –

Cuestiones relacionadas