Как сохранить GMP mpz_t/mpz_class в vector‹byte›?

Мне нужно преобразовать типы mpz_class в vector<byte> и наоборот.
Я реализовал эти две функции, но двустороннее преобразование не работает.

typedef unsigned char byte;

std::vector<byte> mpz_to_vector(std::shared_ptr<mpz_class> x) {
    size_t size;
    byte *a = (byte *) mpz_export(NULL, &size, 1, 1, 1, 0,x->get_mpz_t());
    std::vector<byte> p(a,a+size);
    free(a);
    return p;
}

std::shared_ptr<mpz_class>vector_to_mpz(std::vector<byte> d) {
    mpz_class ptr;
    mpz_import(ptr.get_mpz_t(), d.size(), 1, sizeof(mpz_t), 1, 0, (void *) d.data());
    auto tmp = std::shared_ptr<mpz_class>(new mpz_class(ptr));
    return tmp;
}

person danieltorres    schedule 03.06.2014    source источник
comment
избегайте динамических выделений, особенно ручных: почему size является указателем на динамически выделенное size_t? Также нет необходимости выделять временный буфер в mpz_export. Руководство содержит правильный алгоритм для определения размера выходного буфера.   -  person Deduplicator    schedule 03.06.2014
comment
я удалил динамически выделенный размер. Я не уверен, что понимаю тебя. Думаете, проблема в экспорте или импорте?   -  person danieltorres    schedule 03.06.2014


Ответы (1)


Избегайте динамического распределения, особенно ручного: почему size является указателем на динамически размещаемое size_t?
Вам не нужны никакие временные буферы, поэтому удалите их. В мануале есть правильный алгоритм определения размера выходного буфера.
Применяя его, мы получаем такой экспортер:

std::vector<byte> mpz_to_vector(const mpz_t x) {
    size_t size = (mpz_sizeinbase (x, 2) + CHAR_BIT-1) / CHAR_BIT;
    std::vector<byte> v(size);
    mpz_export(&v[0], &size, 1, 1, 0, 0, x);
    v.resize(size);
    return v;
}
inline std::vector<byte> mpz_to_vector(std::shared_ptr<mpz_class>& x) {
    return mpz_to_vector(x->get_mpz_t());
}

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

std::shared_ptr<mpz_class> vector_to_mpz(const std::vector<byte>& d) {
    auto p = make_shared<mpz_class>();
    mpz_import(p->get_mpz_t(), d.size(), 1, 1, 0, 0, &d[0]);
    return p;
}

Кстати: я использовал make_shared, потому что это более эффективно для хороших реализаций, чем вручную, и обеспечивает безопасность исключений.

person Deduplicator    schedule 03.06.2014
comment
большое тебе спасибо. Можете объяснить арифметику по экспорту? - person danieltorres; 03.06.2014
comment
Простое преобразование из #bits =› #(partial) слова размера b бит. Просто имейте в виду, что деление C++ округляется до 0. В любом случае, это была прямая копия из руководства. - person Deduplicator; 03.06.2014