使用数组外部地址的数组运算符



我最近遇到一个C++类,它实现了一个基于非零索引的数组。也就是说,可以初始化这个类,使其具有一个有效的索引范围,比如15.19。这个类计算索引为0的元素的地址,即使它可能在分配的地址空间之外,并存储该地址。然后,仅通过使用此元素0地址的运算符[]来处理元素访问。一些示例代码(简化):

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的计算中出现算术溢出,即如果最小索引偏移量大于分配器地址,会发生什么。这是否有可能出现严重错误,或者这段代码总是安全的?

你的直觉是正确的

在数组边界之外形成指针是未定义的,溢出是一个非常现实的问题,作者应该按照你的建议来做。

[C++11: 5.7/5]:将具有整型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的一个元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果数组元素和原始数组元素的下标之差等于整数表达式[..]如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象最后一个元素之后的元素,则求值不应产生溢出否则,行为未定义

最新更新