¿El bit std:: array es compatible con el viejo array C?


¿Es la representación de bits subyacente para un std::array<T,N> v y un T u[N] lo mismo?

En otras palabras, ¿es seguro copiar N*sizeof(T) bytes de uno a otro? (Bien a través de reinterpret_cast o memcpy.)

Editar:

Para una aclaración, el énfasis está en la misma representación de bits y reinterpret_cast.

Por ejemplo, supongamos que tengo estas dos clases sobre un tipo trivialmente copiable T, para algunos N:

struct VecNew {
    std::array<T,N> v;
};

struct VecOld {
    T v[N];
};

Y hay la función heredada

T foo(const VecOld& x);

Si las representaciones son las mismas, entonces esta llamada es segura y evita copiar:

VecNew x;
foo(reinterpret_cast<const VecOld&>(x));
Author: cpburnz, 2016-09-07

5 answers

Digo que sí (pero la norma no lo garantiza).

Según [array] / 2:

Una matriz es un agregado ([dcl.init.aggr]) que puede ser lista-inicializada con hasta N elementos cuyos tipos son convertibles a T.

Y [dcl.init.aggr]:

Un aggregate es un array o una clase (Cláusula [clase]) con

  • No hay constructores proporcionados por el usuario, explícitos o heredados ([clase.ctor]),

  • No hay miembros de datos no estáticos privados o protegidos (Cláusula [clase.acceso]),

  • Sin funciones virtuales ([class.virtual]), y

  • No hay clases base virtuales, privadas o protegidas ([class.mi]).

A la luz de esto, "can be list-initialized" solo es posible si no hay otros miembros al principio de la clase y no hay vtable.

Entonces, se especifica data() as:

constexpr T* data() noexcept;

Devuelve: Un puntero tales que [data(), data() + size()) es un rango válido, y data() == addressof(front()).

El estándar básicamente quiere decir "devuelve un array" pero deja la puerta abierta para otras implementaciones.

La única otra implementación posible es una estructura con elementos individuales, en cuyo caso puede encontrarse con problemas de aliasing. Pero, en mi opinión, este enfoque no añade nada más que complejidad. No hay nada que ganar desenrollar una matriz en una estructura.

Así que no tiene ningún sentido no para implementar std::array como una matriz.

Pero existe un vacío legal.

 8
Author: rustyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-08 09:05:43

Esto no responde directamente a su pregunta, pero simplemente debe usar std::copy:

T c[N];
std::array<T, N> cpp;

// from C to C++
std::copy(std::begin(c), std::end(c), std::begin(cpp));

// from C++ to C
std::copy(std::begin(cpp), std::end(cpp), std::begin(c));

Si T es un tipo copiable trivialmente, se compilará hasta memcpy. Si no lo es, entonces esto hará la asignación de copia en cuanto a elementos y será correcta. De cualquier manera, esto hace lo Correcto y es bastante legible. No se necesita aritmética manual de bytes.

 20
Author: Barry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-07 18:48:14

std::array proporciona el método data () que se puede usar para copiar a / desde una matriz de estilo c de tamaño adecuado:

const size_t size = 123;
int carray[size];
std::array<int,size> array;

memcpy( carray, array.data(), sizeof(int) * size );
memcpy( array.data(), carray, sizeof(int) * size );

Como se indica en la documentación

Este contenedor es un tipo agregado con la misma semántica que una estructura que contiene una matriz de estilo C T[N] como su único miembro de datos no estático.

Así que parece que la huella de memoria sería compatible con la matriz de estilo c, aunque no está claro por qué desea utilizar "hacks" con reinterpret_cast cuando hay una adecuada camino que no tiene ninguna sobrecarga.

 12
Author: Slava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-07 18:39:36

El requisito en el método data() es que devuelva un puntero T* tal que:

[data(), data() + size()) es un rango válido, y data() == addressof(front()).

Esto implica que puede acceder a cada elemento secuencialmente a través del puntero data(), por lo que si T es trivialmente copiable, puede usar memcpy para copiar sizeof(T) * size() bytes a/desde un array T[size()], ya que esto es equivalente a memcpy ing cada elemento individualmente.

Sin embargo, no puede usar reinterpret_cast, ya que eso violaría estrictamente el aliasing, como data() no es necesario para que en realidad esté respaldado por un array - y también, incluso si tuviera que garantizar que std::array contiene un array, ya que C++17 no puede (incluso usando reinterpret_cast) enviar un puntero a un array a/desde un puntero a su primer miembro (tiene que usar std::launder).

 9
Author: ecatmur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-07 18:55:48

array no exige mucho sobre el tipo subyacente sobre el que lo instancias.

Para tener cualquier posibilidad de resultados útiles al usar memcpy o reinterpret_cast para hacer una copia, el tipo sobre el que lo instanciaste tendría que ser trivialmente copiable. Almacenar esos elementos en un array no afecta el requisito de que memcpy (y tales) solo funcionen con tipos copiables trivialmente.

array se requiere que sea un contenedor contiguo y un agregado, que bastante mucho significa que el almacenamiento de los elementos debe ser una matriz. El estándar lo muestra como:

T elems[N]; // exposition only

Más tarde, sin embargo, tiene una nota que al menos implica que se requiere un array (§[array.sinopsis] / 4):

[Nota: La variable miembro elems se muestra solo para exposición, para enfatizar que array es un agregado de clase. El nombre elems no es parte de la interfaz del array. -nota final]

[subrayado añadido]

Note cómo es realmente solo el nombre específico elems que no es necesario.

 6
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-07 18:57:33