【问题标题】:How do I properly use a dynamically-allocated opaque pointer in a scoped pointer class?如何在作用域指针类中正确使用动态分配的不透明指针?
【发布时间】:2011-08-09 00:01:12
【问题描述】:

背景

我正在使用英特尔 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

【问题讨论】:

    标签: c++ casting smart-pointers opaque-pointers


    【解决方案1】:

    你说得对:

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

    但这给了你两个局部变量,你必须记住在你完成temparray 之后不要保留shaCtx。因此,滚动您自己的包装器是一个非常吸引人的选择,因为它为您提供了安全性。

    您当前的 IppsScopedState 很好,但我建议稍微调整一下,以便在内部使用 boost::scoped_array,添加 operator-&gt; 访问器和 const 访问:

    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-&gt; 和 const get() 可能是多余的,而且是不必要的。

    所以,最后,我会推荐您的自定义包装器,并使用 reinterpret_cast 而不是旧的 c 样式强制转换语法。

    【讨论】:

    • 感谢您在我的帖子中提出要点。由于这些英特尔加密结构是不透明的,它们都没有任何可访问的成员,因此我不需要operator-&gt;。因为这是我的第一个问题,所以我不能赞成你的回答,但我会在做一些简短的测试后接受它。
    【解决方案2】:

    您可以使用boost::scoped_array 或仅使用std::vector

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多