Как правильно использовать динамически размещаемый непрозрачный указатель в классе указателя с областью видимости? - PullRequest
1 голос
/ 09 августа 2011

Фон

Я работаю с криптографическими библиотеками Intel IPP для тестирования.

Они определяют несколько непрозрачных структур, используемых для общих контекстов над такими вещами, как хеширование и шифрование, которые, конечно, не могут быть непосредственно созданы.

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

Их примеры работают примерно так:

int byteSize = 0;
ippsSHA256GetSize(&byteSize);

// IppsSHA256State shaCtx; // Error: incomplete type is not allowed
IppsSHA256State * shaCtx = (IppsSHA256State *)(new uint8_t[byteSize]);
// use shaCtx
delete [] (uint8_t *)shaCtx;

Вопрос

Как правильно обернуть это в класс указателя с областью видимости, чтобы мне не пришлось беспокоиться об освобождении?


Вещи, которые я пробовал

Я думаю, что следующее не будет безопасным, поскольку вызов delete в деструкторе будет иметь тип T, а не delete [] в массиве, который был на самом деле Распределить:

boost::scoped_ptr<IppsSHA256State> ctx(
    reinterpret_cast<IppsSHA256State *>(new uint8_t[byteSize])
    );

Другой (упрощенный) вариант, который я рассмотрел, - это мой собственный класс указателей с областью видимости, но приведение к нему заставляет меня сомневаться в правильности этого, хотя мое понимание reinterpret_cast таково, что при приведении назад к исходному типу не должно быть никакой двусмысленности:

template <typename T>
class IppsScopedState
{
public:
    explicit IppsScopedState(size_t byteSize)
        : _ptr(reinterpret_cast<T *>(new uint8_t[byteSize]))
    {}

    T * get() const { return _ptr; }

    ~IppsScopedState(void) {
        if (_ptr) delete [] reinterpret_cast<uint8_t *>(_ptr);
    }
private:
    T * _ptr;
    //NUKE_COPYASSIGN_CONSTRUCTORS
};

Наконец, я рассмотрел небольшое отклонение от вышесказанного:

template <typename T>
class IppsScopedState
{
public:
    explicit IppsScopedState(size_t byteSize)
        : _ptr(new uint8_t[byteSize])
    {}

    T * get() const { return reinterpret_cast<T *>(_ptr); }

    ~IppsScopedState(void) {
        if (_ptr) delete [] _ptr;
    }
private:
    uint8_t * _ptr;
    //NUKE_COPYASSIGN_CONSTRUCTORS
};

В любом случае использование будет таким:

IppsScopedState<IppsSHA256State> ctx(byteSize); // after querying for the byteSize, of course

Ответы [ 2 ]

0 голосов
/ 09 августа 2011

Вы правы, что это:

boost::scoped_ptr<IppsSHA256State> ctx(
    reinterpret_cast<IppsSHA256State *>(new uint8_t[byteSize])
);

Это плохая идея по двум причинам: вместо delete[] будет вызван delete, и он будет удалять неправильный тип.

boost::scoped_array Должно работать нормально:

boost::scoped_array<uint8_t> temparray (new uint8_t[byteSize]);
IppsSHA256State * shaCtx = (IppsSHA256State *)(temparray.get());

Но это дает вам две локальные переменные, и вы должны помнить, что не следует сохранять shaCtx после того, как вы закончите с temparray. Таким образом, прокатка собственной обертки - очень привлекательный вариант, потому что это обеспечивает вам безопасность.

Ваш текущий IppsScopedState в порядке, но я бы посоветовал слегка его настроить, чтобы использовать внутреннюю поддержку boost :: scoped_array, добавить аксессор operator-> и постоянный доступ:

template <typename T>
class IppsScopedState
{
public:
    explicit IppsScopedState(size_t byteSize)
        : _ptr(new uint8_t[byteSize])
    {}

    const T* operator->() const { return get(); }
    T* operator->() { return get(); }
    const T* get() const  { return reinterpret_cast<const T*> (_ptr.get()); }
    T* get()   { return reinterpret_cast<T*>(_ptr.get()); }

private:
    boost::scoped_array<uint8_t> _ptr;
    //NUKE_COPYASSIGN_CONSTRUCTORS
};

Тогда вы можете легко использовать эту обертку:

IppsScopedState<IppsSHA256State> shaCtx (byteSize);
shaCtx->member;  // access any member of IppsSHA256State
some_function(shaCtx.get());  // pass the IppsSHA256State* to a method

В зависимости от ваших потребностей operator-> и const get() могут быть излишними и ненужными.

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

0 голосов
/ 09 августа 2011

Вы можете использовать boost::scoped_array или просто std::vector.

...