使用jsoncpp创建文件的时候,跟添加的顺序不相同,它是按照字母表给排序过的。
虽然问题没有解决,但是找到一篇很好的文章http://wff8785.blog.163.com/blog/static/8920227020109179151766/
json内部存储object元素是用map存储的,map的特性就是会对每次insert入的<key,value>值,按照key排序,这就要求key的类型具有<号的重载(key的类型是class)。Json::Value内部存储对象类型是用map:<CZString, Value>,CZString 是Value内部定义的字符串类型,并对<小于号做了重载。
那目前我遇到的问题是,我要在value中插入的object对象会被安装key排序,但是我又不希望它安装key排序,我要它按照我输入的顺序给我输出。昨天纠结这个问题一天,本来以为有两个解决办法,但是我一直尝试的那个是行不通的。
方法一:修改"<"号的的重载函数,让它始终返回true。本来兴高采烈的以为要成功了,发现结果输出的顺序是对了,可是每个key对应的值却变成了NULL。猛然反应过来,原来CZString的"<"不是map在insert的时候才调用,其他时候也是有用的。失败~~~
方法二:禁止insert调用"<"重载函数。map类的声明函数是类似这样的:map(key, value, function),function的默认函数是operator <(),当然,在STL中这些是用模版写好的,我还没研究过这个。知道这个方法了,可是还不知道怎么去折腾它。
昨天在这个问题上纠结了很久,基本上吃饭想着它 睡觉想着它 坐车想着它 走路也想着它……不过是问题总会有解决办法的。现在的问题是,我要去研究下map的声明函数是个怎么回事,还有template这个东西。
今天星期天,小妹过来鸟,又要开始奔波的一天了。
===========================
问题终于解决了,经过的一天的纠结,原来就那么简单~~~
class Value
{
……
public:
class JSON_API DisCmp {
public:
bool operator()(const CZString& s1, const CZString& s2) const {
return true; //不做任何处理,直接返回
}
};
//typedef std::map<CZString, Value> ObjectValues; 这个是原来的对象类型的声明函数
typedef std::map<CZString, Value, DisCmp> ObjectValues; //这个是新的,用DisCmp禁用insert排序
……
}
以上,就完成了禁用了往map中插入元素的排序功能的任务。但是这个时候问题其实还没解决,而也是这个问题让我纠结了大半天。因为这个时候我输出的结果是按照我原来的插入顺序了,可是输出地值却仍然全是null。
于是顺着这个思路下去,根据输出结果,排序的问题是解决了,而且也没有调用<号的重载,说明是赋值的时候发生问题。因为我的整个思考深度就只到这里,所以就开始怀疑源码的正确性,很显然,最后我错了……
多亏xiaop的提醒,最后才发现可能是最后输出时候的问题。Writer类输出的时候是根据下标操作符[]进行定位数据的,而在Value中重载[]的实现,是find函数来查找。为什么find()有问题呢?
原来map内部存储数据是用红黑树算法的,那map::find()函数查找值的时候也是根据红黑树的模式进行查找的。而我禁用了insert元素时候的排序功能,就破坏了这种结构,这个时候还用find()查找的话,当然就找不到值了。我的解决办法是,改成了使用遍历,方法如下:
const Value &
Value::operator[]( const char *key ) const
{
JSON_ASSERT( type_ == nullValue || type_ == objectValue );
if ( type_ == nullValue )
return null;
#ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString actualKey( key, CZString::noDuplication );
//wangff----
//ObjectValues::const_iterator it = value_.map_->find( actualKey );
//由于map::find()函数是根据红黑树特性进行查找的,重写了map的insert比较方法之后,
//便破坏了其内部的红黑树特性,因此,这里将find函数改成用遍历查找
ObjectValues::const_iterator it;
for (it=value_.map_->begin(); it!=value_.map_->end(); it++)
{
if (it->first == actualKey)
break;
}
//----------------------
if ( it == value_.map_->end() )
return null;
return (*it).second;
#else
const Value *value = value_.map_->find( key );
return value ? *value : null;
#endif
}