2009-11-13 9 views
5

¿Hay alguna manera de transferir la propiedad de los datos contenidos en un std :: vector (apuntado por, digamos T * data) a otro constructo, evitando tener "datos" convertirse en un puntero colgando después de que el vector sale del alcance?evitando que se liberen datos cuando el vector sale del alcance

EDITAR: NO QUIERO COPIAR LOS DATOS (lo cual sería una solución fácil pero ineficaz).

En concreto, me gustaría tener algo como:

template<typename T> 
    T* transfer_ownership(vector<T>&v){ 
    T*data=&v[0]; 
    v.clear(); 
    ...//<--I'd like to make v's capacity 0 without freeing data 
} 

int main(){ 
    T*data=NULL; 
    { 
     vector<double>v; 
     ...//grow v dynamically 
     data=transfer_ownership<double>(v); 
    } 
    ...//do something useful with data (user responsible for freeing it later) 
    // for example mxSetData(mxArray*A,double*data) from matlab's C interface 
} 

La única cosa que viene a la mente para emular esto es:

{ 
    vector<double>*v=new vector<double>(); 
    //grow *v... 
    data=(*v)[0]; 
} 

y luego posteriormente ser liberados ya sea de datos o (en mi caso) utilizado como mxSetData (mxArray A, datos dobles). Sin embargo, esto da como resultado una pequeña pérdida de memoria (estructura de datos para manejar la capacidad, el tamaño, etc. de v), pero no los datos en sí mismos, por supuesto).

¿Es posible sin fugas?

+0

Eso es bastante confuso. Además, intente preguntar en un foro de C++. – Nzbuu

+0

mxSetData y mxArray son parte de la interfaz C de matlab (a través de archivos C mex). – spirov

+0

Sí, pero en realidad no es una pregunta de Matlab *: las personas que saben que Matlab vendrá para ayudarlo no podrán contribuir con nada a menos que conozcan C++. – quark

Respuesta

0

¿Algo como esto funciona para usted?

int main() 
{ 
    double *data = 0; 
    { 
     vector<double> foo; 
     // insert some elements to foo 

     data = new double[foo.size()]; 
     std::copy(foo.begin(), foo.end(), &data[0]); 
    } 

    // Pass data to Matlab function. 
    delete [] data; 
    return 0; 
} 
5

Una solución sencilla sería intercambiando el vector con uno es el propietario:

vector<double> myown; 

vector<double> someoneelses = foo(); 

std::swap(myown, someoneelses); 

Un enfoque más duro, pero quizás mejor es escribir su propio asignador para el vector, y dejar que se asigne a cabo de una piscina usted mantiene Sin experiencia personal, pero no es demasiado complicado.

+0

Simple, "limpio" y muy efectivo desde la solución de perspectiva de rendimiento. myown se puede crear en heap o en otro lugar, para poder vivir después de que alguien está fuera del alcance. –

+1

o incluso más corto: 'foo(). Swap (myown);' – sellibitze

+0

Gracias por señalar los asignadores personalizados. Heredé el asignador en un allocator_derived con comportamiento personalizado (teniendo cuidado de no eliminar si el usuario establece algún marcador, es decir, justo antes de liberar el vector). Esto funciona bien y no se filtra con algún cuidado ... en algunos sistemas, pero no todos desafortunadamente. Por ejemplo, funciona en mac (gcc 4.2.1) pero en Linux de 64 bits (gcc 4.3), el vector declarado como vector > ni siquiera parece usar el comportamiento derivado; No estoy seguro por qué. – spirov

1

Si su vector contiene valores, solo puede copiarlos (lo que sucede cuando llama a std :: copy, std :: swap, etc.). Si mantiene objetos no primitivos en un vector y no desea copiarlos (y los utiliza en otra estructura de datos), considere guardar punteros

5

El objetivo de usar un std :: vector es no tener que preocuparse por los datos en él:

  • Mantenga su vector a lo largo de su aplicación;
  • Pásalo por const-ref a otras funciones (para evitar copias innecesarias);
  • Y las funciones de alimentación esperan un puntero a T con &v[0].

Si realmente no desea mantener su vector, tendrá que copiar sus datos - no se puede transferir la propiedad debido a std::vector garantiza que va a destruir su contenido cuando se va fuera de alcance. En ese caso, use el algoritmo std::copy().

+1

+1 por mencionar el constructo '& v [0]' para la compatibilidad con la interfaz tipo C. –

+0

El tercer elemento es la clave, porque pasar el contenido del vector a las funciones externas sin copiar es una gran parte de lo que quiere el OP. – quark

-2

Dado que no desea copiar datos entre contenedores, pero desea transferir la propiedad de los datos entre contenedores, sugiero usar un contenedor de punteros inteligentes de la siguiente manera.

void f() 
{ 
    std::vector<boost::shared_ptr<double> > doubles; 
    InitVector(doubles); 

    std::vector<boost::shared_ptr<double> > newDoubles(doubles); 
} 

Realmente no se puede transferir la propiedad de los datos entre los contenedores estándar sin hacer una copia de la misma, ya que los contenedores estándar siempre se copian los datos que encapsulan. Si desea minimizar la sobrecarga de copiar objetos costosos, entonces es una buena idea usar un puntero inteligente contado de referencia para envolver su costosa estructura de datos.boost::shared_ptr es adecuado para esta tarea, ya que es bastante barato hacer una copia.

Cuestiones relacionadas