Интеллектуальные указатели с библиотекой, написанной на C

StackOverflow https://stackoverflow.com/questions/498582

Вопрос

Я использую C ++ с библиотекой OpenCV, которая является библиотекой обработки изображений, хотя это не имеет отношения к данному вопросу.В настоящее время мне нужно принять дизайнерское решение.

OpenCV, будучи библиотекой C, имеет свои структуры данных (такие как CvMat), объявленные как structs .Для их создания вы используете такие функции, как cvCreateMat, а для их выпуска вы используете такие функции, как cvReleaseMat.Будучи программистом на C ++, я создал специальный cv_scoped класс, который автоматически вызывал бы cvReleaseMat, когда он выходил за пределы области видимости (например boost::scoped_ptr).

Что я сейчас понимаю, так это то, что я хотел бы использовать auto_ptr и shared_ptr в том числе и в случаях.Я просто чувствую, что пишу код для своего собственного cv_auto_ptr и cv_shared_ptr занятия были бы плохой идеей, не говоря уже о пустой трате времени.Итак, я искал решения, и мне в голову пришли три варианта.

Первый, Я мог бы использовать класс cv_scoped, который я уже создал.Я бы переименовал его в cv_ptr а затем используйте умные указатели следующим образом: std::auto_ptr<cv_ptr>.Однако самое неприятное в этом то, что мне всегда приходилось дважды разыменовывать:

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

Я знаю, это выглядит так, как будто я мог бы объявить неявное преобразование, но на самом деле я не мог - большинство функций OpenCV имеют параметр void * - поэтому неявное преобразование не вызывалось бы.Мне бы очень хотелось найти способ сделать это так, чтобы мне не приходилось выполнять двойное разыменование.

Второй, Я мог бы каким - то образом переопределить operator delete.Я не хочу переопределять глобальный оператор delete, потому что я бы хотел, чтобы это применялось только к CvMat (и нескольким другим) типам.Однако я не могу изменить библиотеку, поэтому я не могу добавить operator delete к структуре CvMat.Так что я не знаю, как это будет работать.

Третий, Я мог бы просто переписать свой собственный auto_ptr, scoped_ptr, и shared_ptr.Это небольшие классы, так что это было бы не слишком сложно, но я просто чувствую, что это плохой дизайн.Если бы я должен был это сделать, я бы, вероятно, сделал что-то в этом роде:

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
}

Что бы вы сделали в моей ситуации?Пожалуйста, помогите мне разобраться с этим.

Это было полезно?

Решение

auto_ptr действительно предназначены для RAII в классе C ++ с конструкциями / деструкторами, которые вы применяете здесь к вещам, для которых они, вероятно, не должны использоваться (но могут).

В любом случае, не хотите ли вы иметь возможность использовать свой объект C ++ так, как если бы это была обычная стековая переменная, без динамического выделения каждый раз?

Стандартным решением вашей проблемы является создание оболочки с конструктором / деструктором.
Но чтобы сделать его пригодным для использования функциями C, просто добавьте оператор внутреннего приведения, чтобы он автоматически волшебным образом преобразовывался обратно в объект C при передаче в функцию C.

Напишите класс-оболочку.

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

Другие советы

Один из подходов, который вы могли бы рассмотреть, заключается в использовании того факта, что std::tr1::shared_ptr обладает функциональностью для предоставления пользовательского средства удаления.Я не знаком с OpenCV, поэтому делаю вывод из того, что вы написали.

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

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

Поскольку средство удаления хранится в общем указателе, вы можете просто использовать его как обычно, и когда общий необработанный указатель, наконец, потребуется удалить, cvReleaseMat будет вызываться по мере необходимости.Обратите внимание , что auto_ptr и scoped_ptr являются гораздо более легкими классами, поэтому не обладают функциональностью для пользовательских удалителей, но если вы готовы к небольшим накладным расходам, то shared_ptr может быть использован вместо них.

Если все, о чем вы заботитесь, - это безопасность исключений, делайте это каждый раз, когда используете матрицы:

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

Если, с другой стороны, вы хотите вменяемый решение: сделайте все возможное и напишите полную оболочку.

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

}

Идти средним путем, используя мешанину универсальных интеллектуальных указателей и "cv_ptrs", звучит как рецепт головной боли и ненужных осложнений.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top