Question

J'utilise C ++ avec la bibliothèque OpenCV, qui est un traitement d'image de la bibliothèque, bien que ce ne soit pas pertinent pour cette question. Actuellement, j'ai une décision de conception à prendre.

OpenCV, en tant que bibliothèque C, a ses structures de données (telles que CvMat) déclarées en tant que structs. Pour les créer, vous utilisez des fonctions comme cvCreateMat, et pour les libérer, vous utilisez des fonctions comme cvReleaseMat. En tant que programmeur C ++, j'ai créé une classe cv_scoped spéciale qui appellerait automatiquement cvReleaseMat lorsqu'elle disparaîtrait de la portée (comme boost::scoped_ptr).

Ce que je réalise maintenant, c'est que j'aimerais pouvoir utiliser auto_ptr et shared_ptr également. Je pense juste qu'écrire du code pour mes propres cv_auto_ptr et cv_shared_ptr classes serait une mauvaise idée, sans parler d'une perte de temps. J'ai donc cherché des solutions et j'ai proposé trois possibilités.

Tout d'abord , je pourrais utiliser la classe cv_scoped que j'ai déjà créée. Je le renommerais en cv_ptr puis j'utiliserais des pointeurs intelligents comme suit: std::auto_ptr<cv_ptr>. Ce qui est gênant à ce sujet, c’est qu’il me faudrait toujours déréférencer deux fois:

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

Je sais qu'il semble que je pourrais déclarer une conversion implicite, mais je ne pouvais pas réellement - la plupart des fonctions d'OpenCV ont le paramètre void * - donc aucune conversion implicite ne serait appelée. J'aimerais vraiment pouvoir le faire sans avoir à faire la double déréférence.

Deuxièmement, , je pourrais remplacer operator delete. Je ne veux pas écraser l'opérateur global delete car je voudrais que cela s'applique uniquement aux types CvMat (et à quelques autres). Cependant, je ne peux pas changer la bibliothèque, donc je ne peux pas ajouter scoped_ptr à la structure CvMat. Donc, je ne sais pas comment cela fonctionnerait.

Troisième , je pourrais simplement réécrire mes propres <=>, <=> et <=>. Ce ne sont pas de grandes classes, donc ce ne serait pas trop difficile, mais je pense que c'est un mauvais design. Si je devais faire cela, je ferais probablement quelque chose dans ce sens:

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
}

Que feriez-vous dans ma situation? S'il vous plaît, aidez-moi à comprendre celui-ci.

Était-ce utile?

La solution

Les auto_ptr sont vraiment conçus pour les classes RAII sur C ++ avec les constructions / destructeurs que vous poussez ici pour des utilisations pour lesquelles ils ne devraient probablement pas être utilisés (mais que vous pouvez).

Quoi qu'il en soit, ne voulez-vous pas pouvoir utiliser votre objet C ++ comme s'il s'agissait d'une variable de pile normale sans allouer dynamiquement à chaque fois?

La solution standard à votre problème consiste à créer un wrapper avec constructeur / destructeur.
Mais pour le rendre utilisable par les fonctions C, il suffit d’ajouter un opérateur de conversion interne afin qu’il se reconvertisse automatiquement par magie en objet C lorsqu’il est passé à une fonction C

Écrivez une classe de wrapper.

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);
}

Autres conseils

Une approche que vous pourriez envisager consiste à utiliser le fait que std::tr1::shared_ptr possède la fonctionnalité nécessaire pour fournir un suppresseur personnalisé. Je ne connais pas OpenCV, je déduis donc de ce que vous avez écrit.

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

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

Etant donné que le suppresseur est stocké dans le pointeur partagé, vous pouvez simplement l'utiliser comme d'habitude. Lorsque le pointeur brut partagé doit enfin être supprimé, cvReleaseMat sera appelé selon les besoins. Notez que auto_ptr et scoped_ptr sont des classes beaucoup plus légères. Par conséquent, vous ne disposez pas des fonctionnalités pour les déléteurs personnalisés. Toutefois, si vous êtes prêt à supporter un temps système réduit, shared_ptr peut être utilisé à leur place.

Si vous ne vous souciez que de la sécurité des exceptions, faites-le à chaque fois que vous utilisez des matrices:

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

Si, par contre, vous souhaitez une solution rationnelle , parcourez un kilomètre supplémentaire et écrivez un wrapper complet.

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;
};

}

En allant au milieu, en utilisant une combinaison de pointeurs intelligents génériques et de & "cv_ptrs &"; sonne comme une recette pour des maux de tête et une complication inutile.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top