C ++ Builder 10.2 Токио> JSON> замена JSONvalue приводит к «нарушению доступа» с JsonValue-> Free () - PullRequest
0 голосов
/ 07 мая 2019

Моя среда:

  • RadStudio 10.2 Токио
  • Работа в Windows 10 (64bit) v1809

Я искал способ заменить значение JSON. Затем я наткнулся на следующие вопросы: А.

В Delphi:

JoPair.JsonValue.Free;
JoPair.JsonValue := TJSONNumber.Create(123);

После этого, я думал, это будет в C ++ Builder

JoPair->JsonValue->Free();
JoPair->JsonValue = new TJSONNumber(123);

Однако это вызвало ошибку «нарушение прав доступа» в ToString ();

Вместо этого я закомментировал JoPair->JsonValue->Free();, тогда без проблем.

Вопрос:

В C ++ Buidler, мне нужно Free JoPair-> JsonValue?

Но без освобождения JsonValue это может привести к утечке памяти.

исходный код

Ниже приведен код, который я проверил

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DBXJSON.hpp> // for JSON
#include <memory> // for unique_ptr
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    String srcFileName = L"test.json";  // source
    String dstFileName = L"out.json";  // destination
    String targetKeySubString = L"hogehoge";  //
    String targetValue = "9";

    // 1. read JSON strings
    std::unique_ptr<TStringList> slread(new TStringList);
    slread->LoadFromFile(srcFileName);

    // 2. replace values for the key (target is checked by substring)
    TJSONObject *jsonObj;
    String jsonKey, jsonValue;
    TJSONPair *pairObj;

    std::unique_ptr<TStringList> slwrite(new TStringList);

    for(int li=0; li < slread->Count; li++) { // file line index
        String jsonText = slread->Strings[li];
        // this is needed for avoiding error caused by the file path treating backslash
        jsonText = StringReplace(jsonText, L"\\", L"\\\\", TReplaceFlags()<<rfReplaceAll);
        //
        jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));

        for(int pi=0; pi < jsonObj->Size(); pi++) { // pair index
            pairObj = jsonObj->Get(pi);
            jsonKey = pairObj->JsonString->Value();
            jsonValue = pairObj->JsonValue->Value();

            if (jsonKey.Pos(targetKeySubString) == 0) {
                continue;
            }

            // replace value
            // (ref: https://stackoverflow.com/questions/33426576/delphi-xe7-how-to-change-a-json-value-using-system-json-versus-superobject)
            //
            //pairObj->JsonValue->Free();  // commented out because this causes "access violation" in ToString()
            pairObj->JsonValue = new TJSONString(targetValue);

            // debug
            //ShowMessage(jsonKey + ":" + jsonValue);
        }

        slwrite->Add(jsonObj->ToString());
    }
    jsonObj->Free();

    // 3. output 
    slwrite->SaveToFile(dstFileName);

    ShowMessage(L"Done");

}
//---------------------------------------------------------------------------

Пример

{"1_hogehoge":"3", "2_fugafuga":"1","3_hogehoge":"4", "4_fugafuga":"1", "5_hogehoge":"5", "6_fugafuga":"9"}
{"1_hogehoge":"9","2_fugafuga":"1","3_hogehoge":"9","4_fugafuga":"1","5_hogehoge":"9","6_fugafuga":"9"}

Исходный код (10,2 Токио)

Я обновил исходный код. Все та же проблема.

Я также использовал ToJSON() вместо ToString() с той же ошибкой (нарушение прав доступа) `.

Я также попытался использовать std::unique_ptr, что вызвало еще одну ошибку. Поэтому я отказался от использования std::unique_ptr по этой теме сейчас (возможно, лучше исследовать отдельно).

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <System.JSON.hpp>
#include <memory> // for unique_ptr
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    String srcFileName = L"test.json";  // source
    String dstFileName = L"out.json";  // destination
    String targetKeySubString = L"hogehoge";  //
    String targetValue = "9";

    // 1. read JSON strings
    std::unique_ptr<TStringList> slread(new TStringList);
    slread->LoadFromFile(srcFileName);

    // 2. replace values for the key (target is checked by substring)
    TJSONObject *jsonObj;
    //std::unique_ptr<TJSONObject> jsonObj(new TJSONObject);
    String jsonKey, jsonValue;
    TJSONPair *pairObj;

    std::unique_ptr<TStringList> slwrite(new TStringList);

    for(int li=0; li < slread->Count; li++) { // file line index
        String jsonText = slread->Strings[li];
        // this is needed for avoiding error caused by the file path treating backslash
        jsonText = StringReplace(jsonText, L"\\", L"\\\\", TReplaceFlags()<<rfReplaceAll);
        //
        jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));

        if (jsonObj == NULL) {
            continue;
        }

        for(int pi=0; pi < jsonObj->Count; pi++) { // pair index
            pairObj = jsonObj->Pairs[pi];
            jsonKey = pairObj->JsonString->Value();
            jsonValue = pairObj->JsonValue->Value();

            if (jsonKey.Pos(targetKeySubString) == 0) {
                continue;
            }

            // replace value
            // (ref: https://stackoverflow.com/questions/33426576/delphi-xe7-how-to-change-a-json-value-using-system-json-versus-superobject)
            //
            //pairObj->JsonValue->Free();  // commented out because this causes "access violation" in ToString()

            delete pairObj->JsonValue;

            pairObj->JsonValue = new TJSONString(targetValue);

            // debug
            //ShowMessage(jsonKey + ":" + jsonValue);
        }
        //String res = jsonObj->ToJSON();   // *** access violation ***
        String res = jsonObj->ToString();  // *** access violation ***
        slwrite->Add(res);
        jsonObj->Free();
    }

    // 3. output
    slwrite->SaveToFile(dstFileName);

    ShowMessage(L"Done");

}
//---------------------------------------------------------------------------
...