2015-12-29 2 views
3

Я пытаюсь использовать mupdf для создания программы (в Qt), которая позволит мне перечислить объекты документа в виде списка и позволить мне выбирать, какие объекты визуализировать/не отображать. Поскольку Qt является C++, и мне более комфортно с ним, я пытаюсь обернуть структуры, определенные в mupdf в классах C++.Как создать пользовательский делектор для члена класса unique_ptr, который обертывает c-функцию, которая требует 2 аргумента?

Прямо сейчас моя проблема в этом - одна из первых вещей, которые вы делаете в mupdf, - создать глобальный контекст, который передается всему, включая функции, которые очищают и удаляют структуры.

Я знаком с созданием объекта, который имеет перегруженный operator(), так же, как:

struct ContextDeleter 
{ 
    inline void operator()(fz_context* ctx) 
    { 
     fz_drop_context(ctx); 
    } 
}; 

который я тогда руку unique_ptr -

std::unique_ptr<fz_context, ContextDeleter> ctxPtr; 

То, что я не могу понять, как сделать то же самое с такой функцией, как:

fz_drop_page(ctx, page); 

ie:

struct PageDeleter 
{ 
    inline void operator()(fz_context* ctx, fz_page* pg) 
    { 
      fz_drop_page(ctx, pg); 
    } 
} 

Это, очевидно, неверно, но это то, чего я пытаюсь достичь.

Как создать deleter для unique_ptr, который включает в себя 2 аргумента (в этом случае необходимый указатель контекста)? Есть ли способ сделать так, чтобы unique_ptr знал об указателе контекста для удаления страницы (в этом примере)? Или (как мне показалось, мне нужно) создать что-то, что обертывает unique_ptr, поэтому я могу каким-то образом передать ему контекст для удаления (еще не до конца додумался).

Я видел примеры здесь:

How do I use a custom deleter with a std::unique_ptr member?

и

Wrapping of C-code with a unique_ptr and custom deleter

, но я не могу понять, как заставить их работать в моем случае.

ответ

6

МАГАЗИНУ fz_context * в Deleter, и передать экземпляр этого Deleter к unique_ptr, который держит fz_page *

struct PageDeleter 
{ 
    explicit PageDeleter(fz_context *ctx) 
    : ctx(ctx) 
    {} 
    void operator()(fz_page* page) const 
    { 
     fz_drop_page(ctx, page); 
    } 
    fz_context *ctx; 
}; 

Построить unique_ptr в

fz_context *ctx = // get the fz_context 
fz_page *page = // get the fz_page 

PageDeleter page_del(ctx); 
std::unique_ptr<fz_page, PageDeleter> pagePtr(page, page_del); 

Вы можете обернуть все это в a make_unique_fz_page функция для удобства.

+0

Unfortunetally, C++ не имеет понятия аргументов деструкторов: если это так, вы могли бы уменьшить состояние ваших уникальных PTRS налетом. Это была бы странная, сложная языковая функция, которая добавила бы methinks. – Yakk

+0

OP ищет реализацию 'PageDeleter', но вместо этого в вашем примере реализован' ContextDeleter', для которого OP уже имеет рабочую реализацию. Я обновил ваш ответ, чтобы поменять значения вокруг. –

0

Попробуйте использовать лямбда, который фиксирует значение fz_context*, вместо того, чтобы хранить его в пользовательской Deleter:

fz_context *ctx = ...; 
fz_page *page = ...; 

std::unique_ptr<fz_page, std::function<void(fz_page*)>> pagePtr(page, [ctx](fz_page *page){ fz_drop_page(ctx, page); }); 

Или:

fz_context *ctx = ...; 
fz_page *page = ...; 

auto deleter = [ctx](fz_page *page){ fz_drop_page(ctx, page); }; 
std::unique_ptr<fz_page, decltype(deleter)> pagePtr(page, deleter); 
1

Использование std::unique_ptr конструктор с Deleter непосредственно это немного раздражение с лямбдами, потому что вы не можете назвать тип. Но вы можете определить тип, используя шаблоны, как это:

template <typename T, typename D, typename ...Args> 
std::unique_ptr<T,D> make_unique_with_deleter(D deleter, Args&&...args) 
{ 
    return std::unique_ptr<T,D>(
     new T(std::forward<Args>(args)...), 
     std::move(deleter)); 
} 

Таким образом, вы создаете unique_ptr с лямбда-Deleter непосредственно в одном месте. Вот пример:

int main() 
{ 
    const auto ctx = make_unique_with_deleter<fz_context>(
     [](fz_context * ctx){ fz_drop_context(ctx); }, 
     nullptr, nullptr, FZ_STORE_UNLIMITED); 
    const auto page = make_unique_with_deleter<fz_page>( 
     [ctx](fz_page * pg){ fz_drop_page(ctx.get(), pg); }, 
     ctx.get(), 1000000); 
    // and so forth ... 
} 
Смежные вопросы