2012-06-26 19 views
22

¿Hay alguna manera segura y estándar de tratar una matriz de estilo C como una matriz std :: sin copiar los datos en una nueva matriz std ::?Tratar C cstyle array como std :: array

Esto claramente no se compila, pero es el efecto que me gustaría (mi uso real es más complicado pero esta muestra corta debería mostrar lo que me gustaría hacer). Supongo que un reinterpret_cast "funcionará" pero probablemente no es seguro.

#include <array> 

int main() 
{ 
    int data[] = {1, 2, 3, 4, 5}; 

    // This next line is the important one, treating an existing array as a std::array 
    std::array<int, 5>& a = data; 
} 

Parece que debería ser posible ya que los datos deben almacenarse de manera idéntica.

edit: Para ser claros No quiero borrar una nueva std :: array, quiero referirme a los datos existentes como uno solo.

+1

contenedores STL gestionar su propia memoria. No puede crear una matriz y hacer que administre una matriz que haya asignado a otra parte. – krammer

+2

Dado que 'std :: array' y' std :: vector' esperan administrar su propia memoria, debe tener mucho cuidado al usar 'reinterpret_cast' sin tomar medidas para asegurar que no intenten eliminar datos que no sean bajo su control. Pero aparte de eso ... no tengas miedo de 'memcpy'. Es una rutina bastante eficiente, después de todo. – Rook

+0

Ok gracias. Quiero hacer esto de forma segura, no hacer un truco, solo me preguntaba si era posible es todo :) – jcoder

Respuesta

8

No puede hacer eso. El std::array es un agregado y contiene su propio bloque de datos (a diferencia de un puntero a un bloque de datos que se puede reasignar fácilmente). Entonces no hay forma de evitar una copia de todos los elementos. En C++ 11 esto es particularmente importante porque los datos de la matriz no se pueden mover, por lo que no hay una función eficiente std::swap, por ejemplo.

+5

Entiendo eso. No quiero crear una nueva matriz std :: con sus propios datos, quiero referirme a los datos existentes como si fuera una matriz estándar, ya que es probable que tengan el mismo diseño. Si es posible hacerlo de manera segura, eso es todo. Estoy seguro de que un reinterpret_cast "hack" "funcionará" ... – jcoder

+0

upvoted de todos modos como "lo siento, no puedes hacer eso de manera segura" es una buena respuesta a la pregunta, incluso si no es lo que esperaba. – jcoder

7

Puede utilizar reinterpret_cast, sin embargo en cuenta que se trata de un truco sucio feo y no se debe hacer algo como esto en su código de liberación real: pueden surgir

std::array<int, 5> &a = reinterpret_cast<std::array<int, 5>&>(data); 

Los problemas si la aplicación interna de std :: array cambios (p. ej., se agregarán algunos campos adicionales en la versión de depuración de STL para realizar algunas comprobaciones de tiempo de ejecución). Entonces, este código comenzará a fallar sin mensajes informativos (ya que se basa en la suposición implícita de que el objeto std :: array y el array C tienen el mismo diseño de memoria).

Si usted decide ir a por el truco sucio feo, no obstante, al menos agregar un control de tamaño en tiempo de compilación:

C_ASSERT(sizeof(a) == sizeof(data)); 

Esto producirá un error en caso de que el tamaño de std :: gama <> paradas coincidiendo con el tamaño de su matriz C (debido a algunos cambios en la implementación de STL).

+0

Sí, tengo esto para "trabajar". Solo me preguntaba si había una manera de que no fuera un feo y sucio truco :) gracias – jcoder

+3

El nombre 'reinterpret_cast' es intencionalmente feo para dejar en claro que se está usando un hack feo. – MSalters

+0

Gracias, buena respuesta. No iré con un hack sucio. Solo había un caso en mi código donde tenía una matriz de tamaño fijo, así que quería usar std :: array en todo mi código, pero un código antiguo que no puedo cambiar me dio una matriz de estilo c. No haré un truco para eso, pero hubiera sido bueno poder hacer algo eficiente y compatible. – jcoder

15

Como se discutió en este post Is std::array<T, S> guaranteed to be POD if T is POD?

std::array<int, N> es POD y el diseño de este modo estándar. Por lo que entiendo los requisitos de diseño estándar, esto significa que el puntero al objeto es idéntico al puntero del primer miembro. Como std :: array no tiene miembros privados/protegidos (según http://en.cppreference.com/w/cpp/container/array), esto debería estar de acuerdo con el primer elemento de la matriz envuelta. Por lo tanto algo así como

reinterpret_cast< std::array<int, 5>* >(&data)

es en mi opinión garantizado para trabajar por la norma. Debo admitir, sin embargo, que a veces tengo dificultades para interpretar el lenguaje estándar, así que por favor corrígeme si me equivoco.

Saludos Claas

+2

creo que estás en lo correcto, pero me gustaría comprobar que array5 * p = reinterpret_cast < array5* > (y datos); ASSERT (p-> data() == &data); que es lo que finalmente queremos – GameDeveloper