我们都知道C++中的String和Vector的size_type实际上定义为有编译器决定的unsigned型,但是对于unsigned型或许我们需要深入理解一下,通过下面这段程序引入本文的主题:
程序1:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> vect;
vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vect.push_back(4);
for(vector<int>::size_type i=vect.size()-1;i>=0;--i)
{
cout<<i<<": "<<vect.size()<<": "<<vect[i]<<endl;
}
return 0;
}
运行上面程序将会出现如下vector超出索引的异常:
于是我参考程序报错的C++标准源码,
if (size() <= _Pos)
{
_DEBUG_ERROR("vector subscript out of range");
_SCL_SECURE_OUT_OF_RANGE;
}
这是报错的错误,很明显就是一个超出索引的错误,一直没想清楚原因,后来记得C++ Primer中讲过size_type实际上定义为有编译器决定的unsigned型,于是定义为有关unsigned的问题。
程序2:
于是如若将程序做如下修改,则程序正确:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> vect;
vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vect.push_back(4);
//修改循环判断条件
for(vector<int>::size_type i=vect.size()-1;i!=-1;--i)
{
cout<<i<<": "<<vect.size()<<": "<<vect[i]<<endl;
}
return 0;
}
首先解释为什么程序1是错误的:
那为什么改变这两个判定条件会导致程序运行不同呢,原因就在于unsigned型在循环中变到0的时候,再次执行--i时,实际上它是按照0的补码减1的操作,这样实际上内存存储的这个等效于int型的-1的内存存储,为10000000 00000000 00000000 00000001(假设编译器字长为32位机),则实际上的unsigned值为4294967295。这就解释了为什么当循环判断条件为i>=0是会超出索引,这时候i不是-1,而是4294967295,循环判断条件成立,但是输出是i已经超出索引。
然后解释为什么程序2是正确的:
那为什么i!=-1作为循环判断条件是正确的呢?因为当利用关系运算符!=判断一个unsigned和int型是,它实际并不是比较两个值,而是比较两个变量在内存中的存储是否相同,因为unsigned的4294967295和int的-1都是存储为10000000 00000000 00000000 00000001(假设编译器字长为32位机),为了验证这个观点,利用程序3来证明
程序3:
#include "stdafx.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int i=-1;
int j=-1;
if(i==j)
cout<<"i: "<<i<<"\n"<<"j: "<<j<<endl;
else
cout<<"Your opinion is error!!"<<endl;
return 0;
}
运行:
由此可以看出i和j的值肯定是不相等的,i不可能为负值,但是由于他们在内存中存储一样,所以能判断为相等,而且i的值是4294967295。