实用经验 72 重载operator[]的陷阱

使用[]下标操作符,我们可像数组下标访问形式一样访问对象。这种操作方式简单而且形象,又方便理解。

注解:operator[]下标操作符只能作为类的成员函数。

重载operator[]也没我们想象的那么简单。在重载operator[]时,你必须保证他在用作赋值的左右操作数是都能够正常工作,如果下标操作符出现在左边,它可生成左值;如果下标操作符出现在右边它可生产右值。符合这两种假设,operator[]操作符只能使用返回值。

操作符返回引用可以用在赋值的任何一方;除此之外,还需要考虑const对象和非const对象的差异。const对象只能访问const成员函数,而且const对象不允许被修改。应用于const对象时,operator[]应返回const引用,因为不能用在赋值的目标。

最佳实践:定义类的下标操作符时,一般应定义两个版本:一个为非const成员并返回引用。一个为const成员并返回const引用。

来看一个下标操作符重载的例子:

//  数据联合类实现。
class CItems 
{
public:
    CItem &operator[](const int iIndex);
    const CItem &operator[](const int iIndex) const ;
private:
    std::vector<CItem> m_Items;  
}
//左值 [] 操作符重载
CItem &CItems::operator[](const int iIndex) 
{ 
    return m_Items[iIndex];  // 没有进行范围检查。
}
// 右值[] 操作符重载
const CItem &CItems::operator[](const int iIndex)  const
 { 
    return m_Items[iIndex];  // 没有进行范围检查。
 }

这段代码关于operator[]的实现依然存在下标越界问题。那么应如何避免呢?就从这两个重载函数而言,我们无法避免这类问题的出现。因为operator[]只接受一个参数,即下标,所以无法得知传入的下标值是否合法。

但是是否有其他的解决方案呢?比如发现传入的下标非法就立刻抛出异常。我们看这种假设的实现。

CItem &CItems::operator[](const int iIndex) 
{ 
    if ( iIndex < m_Items.size())
	{
    	return m_Items[iIndex];  // 没有进行范围检查。
	}
	else
	{
    	throw();      // 抛出一个异常,明确的告诉开发者,这儿传入的下标值非法了。
	}
}

const CItem &CItems::operator[](const int iIndex)  const
{ 
    if ( iIndex < m_Items.size())
	{
    	return m_Items[iIndex];  // 没有进行范围检查。
	}
	else
	{
    	throw();      // 抛出一个异常,明确的告诉开发者,这儿传入的下标值非法了。
	}
 }

以程序停止运行为代价,提示存在问题,确实有一定的可取之处。但是有时候这种代价未免太大了。如果你的程序运行每天会给客户提供上千万元的效益,然而有一天它突然停止运行了。那么后果可想而知。

还有更好的解决方法吗?答案是有的。有更安全的做法。这种作为其实更简单。就是在每次调用operator[]之前,判断下标值是否合法。

class CItems 
{
public:
    CItem &operator[](const int iIndex);
    const CItem &operator[](const int iIndex) const ;
    int GetMaxIndex();
private:
    std::vector<CItem> m_Items;  
}

int  CItems::GetMaxIndex()
{
    return m_Items.size();
}


// 使用下标操作符号
int  iIndex =  0;
CItems* pItems = new CItems();// 检查下标值是否合法。只有合法的情形下才执行operator[]操作。
if (iIndex < pItems-> GetMaxIndex)
{
   CItem *pItem = pItems[iIndex];
}

两种方案对比

第一种方案:如果下标值越界了,抛出异常。这种方案可在调试过程中使用。在软件发布阶段不适合使用,因为一旦软件抛出异常。客户会为此付出惨痛的代价。

第二种方案:每次通过下标操作时,首先检查下标是否越界。只有在非越界的情况下,才执行下标重载函数。这种方法和第一种方法相比比较安全。只要使用得当,软件不会抛出异常。

请谨记

  • 请注意operator[]下标操作符只能作为类的成员函数。同时在定义类的下标操作符时请定义两个版本。以适应const对象和非const对象。
  • 小心operator[]带来的陷阱。在重载时必须把这部分陷阱考虑进去,以防为此付出惨痛的代价。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值