C++ 如何在作用域指针类中正确使用动态分配的不透明指针? 背景

C++ 如何在作用域指针类中正确使用动态分配的不透明指针? 背景,c++,casting,smart-pointers,opaque-pointers,C++,Casting,Smart Pointers,Opaque Pointers,我正在使用英特尔IPP加密库进行测试 它们定义了几个不透明结构,用于共享上下文,当然不能直接实例化哈希和加密等内容 要初始化其中一个不透明结构,需要查询字节大小,然后动态分配一些字节并强制转换到结构指针 他们的例子是这样的: int byteSize = 0; ippsSHA256GetSize(&byteSize); // IppsSHA256State shaCtx; // Error: incomplete type is not allowed IppsSHA256State

我正在使用英特尔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;
IppsScopedState<IppsSHA256State> ctx(byteSize); // after querying for the byteSize, of course

问题: 用什么合适的方法将其包装在一个作用域指针类中,这样我就不必担心释放问题了?


我尝试过的事情 我认为以下操作不安全,因为析构函数中对delete的调用将在T类型上,而不是在实际分配的数组上调用delete[]

boost::scoped_ptr<IppsSHA256State> ctx(
    reinterpret_cast<IppsSHA256State *>(new uint8_t[byteSize])
    );
boost::有范围的\u ptr ctx(
重新解释铸件(新的uint8[byteSize])
);
我考虑过的另一个(简化的)选项是我自己的一个简单的作用域指针类,但是这里的强制转换让我不确定这是否正确,尽管我对重新解释强制转换的理解是,当强制转换回原始类型时,不应该有任何歧义:

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
};
模板
IPPScopedState类
{
公众:
显式IPPScopedState(大小字节大小)
:_ptr(重新解释演员阵容(新单元8_t[byteSize]))
{}
T*get()常量{return\u ptr;}
~IPPScopedState(无效){
如果(_ptr)删除[]重新解释投射(_ptr);
}
私人:
T*_ptr;
//NUKE_COPYASSIGN_构造函数
};
最后,我考虑了上面的一点变化:

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
};
模板
IPPScopedState类
{
公众:
显式IPPScopedState(大小字节大小)
:\u ptr(新单元8\u t[byteSize])
{}
T*get()常量{return reinterpret_cast(_ptr);}
~IPPScopedState(无效){
如果(_ptr)删除[]_ptr;
}
私人:
uint8_t*_ptr;
//NUKE_COPYASSIGN_构造函数
};
在这两种情况下,用法如下:

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;
IppsScopedState<IppsSHA256State> ctx(byteSize); // after querying for the byteSize, of course
IPPScopedState ctx(字节大小);//当然,在查询byteSize之后

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

您认为这是正确的:

boost::scoped_ptr<IppsSHA256State> ctx(
    reinterpret_cast<IppsSHA256State *>(new uint8_t[byteSize])
);
但这会给您两个局部变量,您必须记住,在使用
temparray
之后,不要保留
shaCtx
。所以,滚动你自己的包装是一个非常吸引人的选择,因为它给了你安全感

您当前的
ippscopedstate
很好,但我建议稍微调整一下,以便在内部使用boost::scoped_数组,添加
操作符->
访问器和常量访问:

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
};
模板
IPPScopedState类
{
公众:
显式IPPScopedState(大小字节大小)
:\u ptr(新单元8\u t[byteSize])
{}
常量T*运算符->()常量{return get();}
T*运算符->(){return get();}
const T*get()const{return reinterpret_cast(_ptr.get());}
T*get(){return reinterpret_cast(_ptr.get());}
私人:
boost::作用域_数组_ptr;
//NUKE_COPYASSIGN_构造函数
};
然后,您可以轻松使用此包装:

IppsScopedState<IppsSHA256State> shaCtx (byteSize);
shaCtx->member;  // access any member of IppsSHA256State
some_function(shaCtx.get());  // pass the IppsSHA256State* to a method
ippscopedstate shaCtx(字节大小);
shaCtx->member;//访问IppsSHA256State的任何成员
一些_函数(shaCtx.get());//将IppsSHA256State*传递给方法
根据您的需要,
操作符->
和const
get()
可能会过度使用,而且不必要


因此,最后,我建议您使用自定义包装器,并在旧的c样式转换语法上使用reinterpret_cast。

感谢您在我的文章中提出这些要点。由于这些英特尔加密结构是不透明的,它们都没有任何可访问的成员,因此我不需要
运算符->
。因为这是我的第一个问题,所以我不能对你的答案投赞成票,但在做了一些简短的测试之后,我会接受它。