Pergunta

Eu estou usando C ++ com a biblioteca OpenCV, que é uma imagem de processamento de biblioteca, embora isso não é relevante para esta pergunta. Atualmente tenho uma decisão de projeto para fazer.

OpenCV, sendo uma biblioteca C, tem suas estruturas de dados (tais como CvMat) declarados como estruturas. Para criá-los, você pode usar funções como cvCreateMat, e para libertá-los, você pode usar funções como cvReleaseMat. Ser um programador C ++, eu criei uma classe cv_scoped especial que chamaria automaticamente cvReleaseMat quando ele saiu do escopo (como boost::scoped_ptr).

O que eu estou percebendo agora é que eu gostaria de poder usar auto_ptr e shared_ptr em casos assim. Eu apenas sinto que escrever código para minhas próprias classes cv_auto_ptr e cv_shared_ptr seria uma má ideia, para não mencionar um desperdício de tempo. Então eu fui à procura de soluções, e eu vim acima com três possibilidades.

Primeiro , eu poderia usar a classe cv_scoped eu já fiz. Eu renomeá-lo para cv_ptr e depois usar ponteiros inteligentes assim: std::auto_ptr<cv_ptr>. A coisa chata sobre isso, porém, é, eu sempre tenho que dereference duas vezes:

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

Eu sei que parece que eu poderia declarar uma conversão implícita, mas eu não podia realmente - a maioria das funções do OpenCV ter o parâmetro void * - então nenhuma conversão implícita seria chamado. Eu realmente como uma maneira de fazer isso, onde eu não tenho que fazer o duplo dereference.

Segunda , eu poderia de alguma forma substituir operator delete. Eu não quero substituir o operador global de eliminar, porque eu só quero que isso se aplica a CvMat (e alguns outros) tipos. No entanto, eu não posso mudar a biblioteca, então eu não posso adicionar operator delete para a estrutura CvMat. Então, eu não sei como isso iria funcionar.

Third , eu poderia simplesmente reescrever minha própria auto_ptr, scoped_ptr e shared_ptr. Eles não são grandes classes de modo que não seria muito difícil, mas eu sinto que isso é mau design. Se eu fosse fazer isso, eu provavelmente faria algo ao longo destas linhas:

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
}

O que você faria na minha situação? Por favor, me ajudar a descobrir isso.

Foi útil?

Solução

O auto_ptr são realmente concebido para RAII na classe C ++ com construções / destruidores você está empurrando seus usos aqui para coisas que eles provavelmente não devem ser usados ??para (mas pode).

De qualquer forma don'y você quer ser capaz de usar seu C ++ objeto como se fosse uma variável de pilha normal sem alocar dinamicamente cada vez?

A solução padrão para o problema é criar um invólucro com construtor / destruidor.
Mas para torná-lo utilizável pelas funções C basta adicionar um operador de conversão interna para que ele auto-magicamente converte-se de volta para o objeto C quando passado para uma função C

Escreva uma classe 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);
}

Outras dicas

Uma abordagem que você poderia considerar é usado o fato de que std::tr1::shared_ptr tem a funcionalidade para fornecer um deleter personalizado. Eu não tenho nenhuma familiaridade com OpenCV por isso estou inferindo a partir do que você escreveu.

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

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

Porque o deleter é loja no ponteiro compartilhada você pode simplesmente usá-lo como normal e quando o ponteiro bruto compartilhada, finalmente, precisa ser excluído, cvReleaseMat serão chamados conforme a necessidade. Note-se que auto_ptr e scoped_ptr são classes muito mais leves por isso não tem a funcionalidade para Deleters personalizados, mas se você está preparado para a pequena sobrecarga, em seguida, shared_ptr pode ser usado em seu lugar.

Se tudo o que importa é a segurança de exceção, fazer isso toda vez que você usar matrizes:

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

Se, por outro lado, você quer um solução, ir a milha extra e escrever um invólucro 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;
};

}

Indo o caminho do meio, usando um podge Hodge de ponteiros inteligentes genéricos e "cv_ptrs" soa como uma receita para dores de cabeça e uma complicação desnecessária.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top