关于jsoncpp内部排序的问题

来源:互联网 发布:网络图片可爱搞笑 编辑:程序博客网 时间:2024/04/29 09:02

使用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
}



原创粉丝点击