代码改变世界

让人头痛的Vector(思索篇)

2004-08-08 00:13  FantasySoft  阅读(...)  评论(...编辑  收藏

        在让人头痛的Vector(提问篇)给大家留了一个问题,hyifeng老大说对了,如果使用vec[0] = 0这种方式的话,"The vector is empty!"是会被打印出来的。然而使用push_back(0),则不会打印出来。
        这是为什么呢?首先,empty()函数的值就是布尔表达式vec.size() == 0的返回值,既然"The vector is empty!"被打印出来,那么就意味着size()的返回值为0了,于是就继续去看size()函数的实现:   

size_type size() const
{
   
return (_First == 0 ? 0 : _Last -
 _First); 
}

        在这里要说明一下:在Vector类当中,定义了三个Iterator:_Last、_First和_End。因为size()返回值为0,那么我们可以想到_Last = _First。而事实上当程序执行reserve()为Vector分配了内存之后,我们可以通过调用begin()和end()函数可以验证_Last 与 _First的初始值是相等。
        难道vec[0] = 0这样的符值方式并不会改变_Last的初始值?接着我查看了"[]" 运算符重载的源代码:

const_reference operator[](size_type _P) const
{
  
return (*(begin() +
 _P)); 
}

        然而在push_back()函数的实现当中,则是调用了insert函数:

void push_back(const _Ty& _X)
{
  insert(end(), _X); 
}

 
iterator insert(iterator _P, 
const _Ty& _X = _Ty())
{
  size_type _O 
= _P -
 begin();
  insert(_P, 
1
, _X);
  
return (begin() +
 _O); 
}


void insert(iterator _P, size_type _M, const _Ty& _X)
{
  
if(_End - _Last <
 _M)
  
{
    size_type _N 
= size() + (_M < size() ?
 size() : _M);
    iterator _S 
= allocator.allocate(_N, (void *)0
);
    iterator _Q 
=
 _Ucopy(_First, _P, _S);
    _Ufill(_Q, _M, _X);
    _Ucopy(_P, _Last, _Q 
+
 _M);
    _Destroy(_First, _Last);
    allocator.deallocate(_First, _End 
-
 _First);
    _End 
= _S +
 _N;
    _Last 
= _S + size() +
 _M;
    _First 
=
 _S; 
   }

   
else if (_Last - _P < _M)
   
{
     _Ucopy(_P, _Last, _P 
+
 _M);
     _Ufill(_Last, _M 
- (_Last -
 _P), _X); 
     fill(_P, _Last, _X);
     _Last 
+=
 _M; 
   }

   
else if (0 < _M)
   
{
     _Ucopy(_Last 
-
 _M, _Last, _Last);
     copy_backward(_P, _Last 
-
 _M, _Last);
     fill(_P, _P 
+
 _M, _X);
     _Last 
+=
 _M; 
   }

}

        由这些代码我们就可以得知,直接通过"[]"操作符去对Vector中element去赋值是不会改变_Last这个iterator的值(事实上如果使用''[]"操作符就会改变_Last的话也是没有意义的),而push_back()则会改变,因此就会产生篇首所说的结果了。