¿Se puede utilizar un RPP compartido para RAII de matrices de estilo C?


Estoy trabajando en una sección de código que tiene muchos puntos de falla posibles que hacen que salga de la función antes. Las bibliotecas con las que estoy interactuando requieren que los arrays de estilo C se pasen a las funciones. Así que, en lugar de llamar a delete en los arrays en cada punto de salida, estoy haciendo esto:

void SomeFunction(int arrayLength)
{
   shared_ptr<char> raiiArray(new char[arrayLength]);
   pArray = raiiArray.get();

   if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }

   //etc.
}

Quería usar unique_ptr, pero mi compilador actual no lo soporta y la sobrecarga de referencia no importa en este caso.

Me pregunto si alguien tiene cualquier pensamiento sobre esta práctica cuando se interactúa con código heredado.

ACTUALIZAR Me olvidé por completo de la shared_ptr llamando delete en lugar de delete []. Simplemente no vi fugas de memoria y decidí ir con ella. Ni siquiera pensé en usar un vector. Desde que he estado profundizando en el nuevo (para mí) C++ últimamente estoy pensando que tengo un caso de "Si la única herramienta que tienes es un martillo, todo parece un clavo." síndrome. Gracias por el feedback.

UPDATE2 Me imaginé Cambiaría la pregunta y daría una respuesta para hacerla un poco más valiosa para alguien que comete el mismo error que yo. Aunque hay alternativas como scoped_array, shared_array y vector, puede usar un shared_ptr para administrar el alcance de una matriz (pero después de esto no tengo idea de por qué querría hacerlo):

template <typename T>
    class ArrayDeleter
    {
    public:
        void operator () (T* d) const
        {
            delete [] d;
        }
    };

void SomeFunction(int arrayLength)
    {
       shared_ptr<char> raiiArray(new char[arrayLength], ArrayDeleter<char>());
       pArray = raiiArray.get();

       if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }

       //etc.
    }
Author: bsruth, 2010-07-16

6 answers

No use shared_ptr o scoped_ptr para mantener punteros a matrices asignadas dinámicamente. shared_ptr y scoped_ptr usan delete ptr; para limpiar cuando el puntero ya no está referenciado/sale del ámbito, lo que invoca un comportamiento indefinido en una matriz asignada dinámicamente. En su lugar, use shared_array o scoped_array, que usan correctamente delete[] ptr; al destruir.

Para responder a su pregunta, si no va a pasar el puntero inteligente, use scoped_array, ya que tiene menos sobrecarga que shared_array.

Alternativamente, use std::vector como almacenamiento de matriz (los vectores tienen asignación de memoria contigua garantizada).

 27
Author: Jon Benedicto,
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
2010-07-16 15:34:20

Use boost::scoped_array, o mejor aún std::vector si está tratando con una matriz.

 15
Author: Nemanja Trifunovic,
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
2010-07-16 15:34:04

Recomiendo encarecidamente simplemente usar un std::vector. Los elementos en vectors se asignan en el montón, y se eliminarán cuando el vector salga del ámbito, dondequiera que salga de la función.

Para pasar un vector al código heredado que requiere matrices de estilo C, simplemente pase &vectorName[0]. Los elementos están garantizados para ser contiguos en la memoria.

 7
Author: Justin Ardini,
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
2010-07-16 15:38:10

Algunas observaciones para los usuarios de C++11:

Para shared_ptr, hay en C++11 un deleter predeterminado para los tipos de matriz definidos en <memory> y compatibles con el estándar (wrt el borrador final) por lo que se puede usar sin deleters adicionales para tales casos:

std::shared_ptr<char> raiiArray(new char[arrayLength], std::default_delete<char[]>()); 

unique_ptr en C++11 tiene una especialización parcial para tratar con new[] y delete[]. Pero no tiene un comportamiento compartido, por desgracia. Debe ser una buena razón para que no haya tal especialización para shared_ptr pero no la busqué, si lo sabes, por favor, compártelo.

 6
Author: mcjoan,
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
2013-08-17 12:41:31

Hay boost::scoped_ptr por esto.

 5
Author: Nikolai Fetissov,
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
2010-07-16 15:30:42

Esto

shared_ptr<char*> raiiArray(new char[arrayLength]);

No es una buena práctica, pero causa un comportamiento indefinido, ya que se asigna con el operador new[], pero shared_ptr utiliza operator delete para liberar la memoria. Lo correcto es usar boost::shared_array o agregar un deleter personalizado.

 3
Author: jpalecek,
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
2010-07-16 15:37:25