【导语】
istringstream支持泛型,可以将字符串格式化特定类型的数据,给开发者的使用带来了很大的方便性。但是,如果使用不当,会带来严重BUG。
【背景】
上周做商旅频道,SVR通过向DB查询数据,供前端展示。但是发现一个让人很困惑的问题:当DB中的字符类型数据以★开头时,前端只会展示★,其后内容根本不展示。
【分析】
这是什么原因呢?起初怀疑MySQL在碰到火星文时会出现数据截断问题,但通过MySQL的命令行工具查看,数据都能正确展示出来,问题肯定不出在MySQL。问题是什么?经过日志跟踪,法线问题就出在了istringstream格式化数据方面!
为减少重复代码,自我封装的数据库操作类使用了泛型编程,通过istringstream来格式化数据:
template<class T>
bool Fetch( uint32_t dwFieldIndex, T &data)
{
const char* ptr = NULL;
if (!_FetchPtr(dwFieldIndex, ptr) || !ptr)
{
assert(ptr != NULL);
return false;
}
std::istringstream buffer;
buffer.str(ptr);
buffer>>data;
return true;
}
问题就出在istringstream上面。当data的类型为string时,istringstream将数据格式化为字符串时,会像cin一样,遇到空白符就停止!
回过头看我的数据时,确实发现每个★后面都跟这一个空格!问题确认了!确认这一个问题,整整花了我一个上午时间。
【其他问题】
istringstream同样在其他方面存在陷阱,必须提前知道这些知识,才能应对自如。
1. 在格式化uint8_t方面存在陷阱。请思考下面这段代码的输出结果是什么?
#include <stdint.h>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char* ptr = "1";
istringstream iss(ptr);
uint8_t ucVal;
iss >> ucVal;
cout << "ptr = " << ptr << "; ucVal = " << (int)ucVal << endl;
return 0;
}
ptr = 1; ucVal = 49
ucVal是49,不是1!是不是出乎你的意料?要让ucVal输出1,那么ucVal的类型必须是int/uint32_t/long之类的。同样, ucVal的类型是int8_t,也会存在和uin8_t相同的问题。