背景
我正在使用"英特尔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])
);
我考虑过的另一个(简化的(选项是我自己的一个简单作用域指针类,但那里的强制转换让我不确定这是否正确,尽管我对relpret_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
您认为这是正确的:
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::scope_array,添加operator->
访问器和const-access:
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->
和常量get()
可能是多余的。
因此,最后,我建议您使用自定义包装器,并在旧的c样式转换语法上使用repret_cast。
您可以使用boost::scoped_array
或仅使用std::vector
。