zoukankan      html  css  js  c++  java
  • json笔记jsoncpp一个全局对象的bug

     今天在工程中使用jsoncpp时,发现一个问题。

    在一个全局对象的析构函数给一个Json::Value赋值的时候,崩溃。现在把问题用一个demo重现出来。如下:

    // ------------------------------------------------------------------------- 
    //    文件名        :    main.cpp
    //    创建者        :    方煜宽
    //    创建时间      :    2012-5-6 22:50
    //    功能描述      :    jsoncpp一个全局对象的bug
    //
    // -------------------------------------------------------------------------
    #include "json.h"
    
    class CA
    {
    public:
        CA();
        virtual ~CA();
    
    protected:
    private:
    };
    
    CA::CA()
    {
    
    }
    
    CA::~CA()
    {
        Json::FastWriter writer;
    
        Json::Value item;
        item[0u] = 0;
        item[1u] = "kuan"; // 到这行时崩溃
    }
    
    CA a;
    
    void main()
    {
    
    }

    提示:

    R6025

    -pure virtual function call

     

    我们在崩溃的地方设置一个断点跟进去。

    发现在json_value.cpp调用下面语句时崩溃。

    {
       value_.string_ = valueAllocator()->duplicateStringValue( value );
    }

     

    查看 valueAllocator() ,src\lib_json\json_value.cpp里,他是一个函数,如下:

    static ValueAllocator *&valueAllocator()
    {
       static DefaultValueAllocator defaultAllocator;
       static ValueAllocator *valueAllocator = &defaultAllocator;
       return valueAllocator;
    }

    它是取得一个静态变量的针指。

    调试发现在使用valueAllocator()时,即DefaultValueAllocator 对象指针时。DefaultValueAllocator 对象已经被析构了。

     

    因为c++中不同的cpp文件中,全局对象和静态对象 构造和析构 顺序是不确定的。

     

    son_value.cpp再看往下看。可以看到。

    static struct DummyValueAllocatorInitializer 
    { DummyValueAllocatorInitializer() { valueAllocator();
    // ensure valueAllocator() statics are initialized before main(). } } dummyValueAllocatorInitializer;

    它的作用是确保valueAllocator()main()函数前被调用。(注意:先构造的后析构,后构造的先析构)

    但其实这样还不能确保在比其它全局对象的构造函数先调用,比其它全局对象晚析构。问题就出在这里了。

     

    解决方案1

    不在全局对象析构函数中使用jsoncpp字符串。就没问题了。

    但有时候会在全局对象析构函数保存一些数据,把它转成json格式后再存盘。所以这个解决方案,治标不治本。

     

    解决方案2

    提前对 DefaultValueAllocator 类对象进行构造,比其它【全部对象】或【静态对象】更前构造,这样DefaultValueAllocator也会比他们更晚析构。

    可以在 DummyValueAllocatorInitializer 前面加上一个编译指令 #pragma init_seg(lib) 如下:

    #pragma init_seg(lib)  // add by fangyukuan 2012.5.6
    static struct DummyValueAllocatorInitializer 
    { DummyValueAllocatorInitializer() { valueAllocator();
    // ensure valueAllocator() statics are initialized before main(). } } dummyValueAllocatorInitializer;

    这个方案,不好的地方就是修改了第三方库。一般我们是不会去修改第三方库的。

    你有更好方案吗?有,请告诉我。

    其它:

    我们再来看看 DefaultValueAllocator 类,都做了些什么?代码如下:

    class DefaultValueAllocator : public ValueAllocator
    {
    public:
       virtual ~DefaultValueAllocator()
       {
       }
    
       virtual char *makeMemberName( const char *memberName )
       {
          return duplicateStringValue( memberName );
       }
    
       virtual void releaseMemberName( char *memberName )
       {
          releaseStringValue( memberName );
       }
    
       virtual char *duplicateStringValue( const char *value, 
                                           unsigned int length = unknown )
       {
          //@todo invesgate this old optimization
          //if ( !value  ||  value[0] == 0 )
          //   return 0;
    
          if ( length == unknown )
             length = (unsigned int)strlen(value);
          char *newString = static_cast<char *>( malloc( length + 1 ) );
          memcpy( newString, value, length );
          newString[length] = 0;
          return newString;
       }
    
       virtual void releaseStringValue( char *value )
       {
          if ( value )
             free( value );
       }
    };

    只有一个功能,malloc 一块内存,把一个指针的数据,拷贝到新内存里。

    我个人感觉,这完全没必要搞一个类成员函数去做这个事。直接写个功能函数不就完了嘛。也不会有今天这个bug了。简洁才是美啊。

    本文地址:http://www.cnblogs.com/fangyukuan/archive/2012/05/07/2486803.html

     

     

  • 相关阅读:
    全端开发必备!10个最好的 Node.js MVC 框架
    action和servlet的关系
    js模块化
    前端类库
    Windows下配置nginx+php(wnmp)
    DllMain的作用
    在linux上实现DllMain + 共享库创建方法
    QT实现Windows下DLL程序编写
    平台相关的宏
    远程线程的注入 PE的修正
  • 原文地址:https://www.cnblogs.com/fangyukuan/p/2486803.html
Copyright © 2011-2022 走看看