Pregunta

Estoy usando C++ con la biblioteca OpenCV, que es una biblioteca de procesamiento de imágenes, a pesar de que no es relevante para esta pregunta.Actualmente tengo una decisión de diseño para hacer.

OpenCV, al ser una biblioteca de C, tiene sus estructuras de datos (tales como CvMat) declaró como structs.Para crear, utilizar funciones como cvCreateMat, y a la liberación de ellos, puede usar funciones como cvReleaseMat.Ser un programador de C++, he creado un especial cv_scoped la clase que se iba a llamar automáticamente a cvReleaseMat cuando salió del ámbito de aplicación (como boost::scoped_ptr).

Lo que estoy darse cuenta ahora es que me gustaría poder usar auto_ptr y shared_ptr en casos así.Creo que la escritura de código para mi propio cv_auto_ptr y cv_shared_ptr las clases serían una mala idea, por no hablar de una pérdida de tiempo.Así que he estado buscando soluciones, y me he encontrado con tres posibilidades.

Primero, Yo podía usar el cv_scoped clase ya he hecho.Me gustaría cambiarle el nombre a cv_ptr y, a continuación, el uso de punteros inteligentes así: std::auto_ptr<cv_ptr>.El molesto cosa acerca de esto, sin embargo, yo siempre iba a tener que eliminar dos veces:

std::auto_ptr<cv_ptr> matrix(cv_ptr(cvCreateMat(320, 240, CV_32FC3)));
cvPow(matrix.get()->get()); // one get for the auto_ptr, one for the cv_ptr

Sé que parece que me podría declarar una conversión implícita, pero yo no podía - la mayoría de las funciones de OpenCV tiene el parámetro void* - así que no hay conversión implícita sería llamado.Realmente me gustaría una forma de hacerlo donde yo no tenga que hacer el doble de eliminar.

Segundo, De alguna manera podría reemplazar operator delete.No quiero reemplazar el operador global eliminar porque yo sólo quiero que esto se aplican a CvMat (y algunos otros) tipos.Sin embargo, yo no puedo cambiar de la biblioteca, así que no puedo agregar operator delete a la CvMat struct.Así que no sé cómo esto iba a funcionar.

Tercera, Yo sólo puedo escribir mi propio auto_ptr, scoped_ptr, y shared_ptr.No son grandes clases por lo que no sería demasiado difícil, pero me siento como que esto es un mal diseño.Si yo fuera a hacer esto, yo probablemente haría algo a lo largo de estas líneas:

class cv_auto_ptr {
public:
  cv_auto_ptr();
  ~cv_auto_ptr();

  // each method would just be a proxy for the smart pointer
  CvMat* get() { return this->matrix_.get()->get(); }
  // all the other operators/methods in auto_ptr would be the same, you get the idea

private:
  auto_ptr<cv_ptr> matrix_; // cv_ptr deletes CvMat properly
}

¿Qué harías en mi situación?Por favor ayudarme a entender esto.

¿Fue útil?

Solución

Los auto_ptr están realmente diseñados para RAII en la clase C ++ con construcciones / destructores a los que está empujando sus usos aquí para cosas para las que probablemente no deberían usarse (pero pueden).

De todos modos, ¿no quieres poder usar tu objeto C ++ como si fuera una variable de pila normal sin asignar dinámicamente cada vez?

La solución estándar a su problema es crear un contenedor con constructor / destructor.
Pero para que las funciones de C puedan usarlo, simplemente agregue un operador de conversión interno para que se convierta automáticamente al objeto de C cuando pase a una función de C

Escribe una clase de contenedor.

class Mat
{
    CvMat* impl;
    public:
        Mat(/* Constructor  Arguments */)
        {
            impl = cvCreateMat(/* BLAH */);
        }
        ~Mat()
        {
            cvReleaseMat(impl);
        }
        operator CvMat*()
        {   // Cast opertator. Convert your C++ wrapper object into C object
            // when you use it with all those C functions that come with the
            // library.

            return impl;
        }
};

void Plop(CvMat* x)
{   // Some C function dealing with CvMat
}

int main()
{                            // Don't need to dynamically allocate
    Mat                  m;  // Just create on the stack.
    Plop(m);                 // Call Plop directly

    std::auto_ptr<Mat>   mP(new Mat);
    Plop(*mP);
}

Otros consejos

Un enfoque que podría considerar es el hecho de que std::tr1::shared_ptr tiene la función de proporcionar una costumbre deleter.No tengo familiaridad con OpenCV, así que estoy inferencia a partir de lo que has escrito.

struct CvMatDeleter
{
    void operator( CvMat* p ) { cvReleaseMat( p ) ; }
};

void test()
{
    std::tr1::shared_ptr< CvMat > pMat( cvCreateMat(320, 240, CV_32FC3), CvMatDeleter() );
    // . . .
}

Debido a que el deleter es la tienda en la compartida puntero sólo se puede utilizar como normal y cuando la compartida raw puntero, finalmente, debe ser eliminado, cvReleaseMat se llama como se requiere.Tenga en cuenta que auto_ptr y scoped_ptr son mucho más ligeros clases, así que no tiene la funcionalidad para la costumbre de deleters, pero si usted está preparado para la pequeña sobrecarga, a continuación, shared_ptr puede ser utilizado en su lugar.

Si lo único que le importa es la seguridad de excepción, hágalo cada vez que use matrices:

void f() {
    try {
        CvMat* mat = cvCreateMat(320, 240, CV_32FC3));
        // ...
    } catch(...) {
        cvReleaseMat(mat);
        throw;
    }
    cvReleaseMat(mat);
}

Si, por otro lado, desea una solución sana , haga un esfuerzo adicional y escriba un contenedor completo.

namespace cv {

class Mat {
public:
    enum Type { /* ... */ };
    Mat(int w, int h, Type type) {
        impl = cvCreateMat(w, h, intFromType(type));
    }

    ~Mat() {
        cvReleaseMat(impl);
    }

    void pow() { // wrap all operations
        cvPow(impl);
    }

private:
    CvMat* impl;
};

}

Yendo a la mitad del camino, usando una mezcla de punteros inteligentes genéricos y " cv_ptrs " Suena como una receta para dolores de cabeza y una complicación innecesaria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top