我最近遇到了一个C ++类,它实现了一个非零索引的数组。即可以将此类初始化为具有15..19的有效索引范围。此类计算索引为0的元素的地址,即使这可能超出分配的地址空间并存储该地址。然后使用此元素0地址通过operator []处理元素访问。一些示例代码(简化):
template <typename T>
class NonZeroArray
{
public:
NonZeroArray(int min_index, int size, T default_element) :
m_min_index(min_index),
m_size(size),
m_default_element(default_element)
{
m_base_address = (T*) malloc(size*sizeof(T));
m_zero_index_adress = m_base_address - min_index;
}
~NonZeroArray()
{
free(m_base_address);
}
T& element(int index)
{
if ( index < m_min_index || index >= m_min_index + m_size)
return m_default_element;
else
return m_zero_index_adress[index];
}
private:
int m_min_index;
int m_size;
T* m_base_address;
T* m_zero_index_adress;
T m_default_element;
};
这对我来说似乎不太复杂。我真的不明白为什么开发人员没有选择通过m_base_address [index + m_min_index]实现元素访问。但更糟糕的是,我担心目前的实施可能会很危险。代码似乎可靠地工作但我想知道如果在m_zero_index_address的计算中存在算术溢出会发生什么,即如果最小索引偏移量大于allocatead地址。是否有可能出现严重错误或者此代码是否安全?
答案 0 :(得分:7)
你的直觉是正确的。
将指针形成为远离数组范围的未定义,溢出是一个非常现实的问题,作者应该完全按照你的建议完成。
[C++11: 5.7/5]:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。 [..] 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。