Destruye std :: vector sin liberar memoria

Digamos que tengo una función para obtener datos en un vector estándar:

void getData(std::vector &toBeFilled) { // Push data into "toBeFilled" } 

Ahora quiero enviar estos datos a otra función, que debería liberar los datos cuando termine:

 void useData(int* data) { // Do something with the data... delete[] data; } 

Ambas funciones (getData y useData) son fijas y no se pueden cambiar. Esto funciona bien al copiar los datos una vez:

 { std::vector data; getData(data); int *heapData = new int[data.size()]; memcpy(heapData, data.data(), data.size()*sizeof(int)); useData(heapData); data.clear(); } 

Sin embargo, esta operación memcpy es costosa y no es realmente necesaria, ya que los datos ya están en el montón. ¿Es posible extraer y usar directamente los datos asignados por el vector estándar? Algo como (pseudocódigo):

 { std::vector data; getData(data); useData(data.data()); data.clearNoDelete(); } 

Editar:

Tal vez el ejemplo no tenga mucho sentido, ya que es posible simplemente liberar el vector después de la llamada a la función para usar Datos. Sin embargo, en el código real, useData no es una función sino una clase que recibe los datos, y esta clase vive más que el vector …

No.

La API que está utilizando tiene un contrato que establece que toma posesión de los datos que le proporciona y que estos datos se proporcionan a través de un puntero. Esto básicamente descarta el uso de vectores estándar.

Con seguridad, Vector siempre liberará la memoria asignada y destruirá de forma segura los elementos que contiene. Eso es parte de su contrato garantizado y no puede desactivarlo.

Debe hacer una copia de los datos si desea apropiarse de ellos … o mover cada elemento a su propio contenedor. O comienza con tu propio new[] en primer lugar (ugh), aunque al menos puedes envolver todo esto en una clase que imita a std::vector y que ya no sea propietario.

Aquí hay un truco horrible que debería permitirte hacer lo que necesitas, pero se basa en un comportamiento indefinido que hace lo más simple que puede. La idea es crear su propio asignador que sea compatible con el diseño con std::allocator y escriba con letra en el vector:

 template  struct CheatingAllocator : std::allocator { using typename std::allocator::pointer; using typename std::allocator::size_type; void deallocate(pointer p, size_type n) { /* no-op */ } // Do not add ANY data members!! }; { std::vector> data; getData(reinterpret_cast&>(data)); // type pun, `getData()` will use std::allocator internally useData(data.data()); // data actually uses your own allocator, so it will not deallocate anything } 

Tenga en cuenta que es tan intrincado e inseguro como los hacks. Se basa en que la distribución de la memoria no cambia y se basa en std::allocator usando new[] dentro de su función de allocate . Yo no usaría esto en el código de producción, pero creo que es una solución (desesperada).


@TonyD señaló correctamente en los comentarios que es muy probable que std::allocator no use el new[] internamente. Por lo tanto, lo anterior probablemente fallará en la delete[] dentro de useData() . El mismo @TonyD también hizo un buen punto sobre el uso de reserve() para (con suerte) evitar la reasignación dentro de getData() . Entonces el código actualizado se vería así:

 template  struct CheatingAllocator : std::allocator { using typename std::allocator::pointer; using typename std::allocator::size_type; pointer allocate(size_type n) { return new T[n]; } void deallocate(pointer p, size_type n) { /* no-op */ } // Do not add ANY data members!! }; { std::vector> data; data.reserve(value_such_that_getData_will_not_need_to_reallocate); getData(reinterpret_cast&>(data)); // type pun, `getData()` will use std::allocator internally useData(data.data()); // data actually uses your own allocator, so it will not deallocate anything }