В вашем коде МНОГИЕ утечки.
Ваш метод parser()
возвращает ссылку JSON&
вместо указателя JSON*
(как это делает ваш метод parse()
). Вы выделяете новый JSON
объект через new
, а затем возвращаете его вызывающей стороне путем разыменования указателя, а затем вызывающая сторона копирует этот объект в другой выделенный JSON
объект (но у вас нет правильного оператора копирования!) и не delete
исходный объект. Вы делаете эту ошибку много раз внутри parse()
и parser()
.
У вас также происходит утечка памяти в вашем методе find_by()
. Ваш метод filter()
возвращает указатель JSON*
на объект new
'ed JSON
, но find_by()
не delete
', если этот объект завершен с его использованием.
Кроме того, когда parser()
встречает токен StartObject
или StartArray
, это new
'sa std::stack
объект, который никогда не будет delete
' d, когда объект JSON
, которому он назначен, уничтожен , Вам нужно добавить деструктор в ваш класс JSON
, чтобы освободить эти std::stack
объекты, а также JSON
объекты, на которые они держат указатели.
Но затем вы сталкиваетесь с другой проблемой, потому что такой деструктор сломается, если filter()
когда-либо вызывается, потому что он возвращает new
'd JSON
объект, который содержит указатели на значения, которые принадлежат другому JSON
объект. При delete
'отфильтрованном объекте JSON
эти значения будут уничтожены, что приведет к повреждению исходного JSON
объекта, который был отфильтрован.
Кроме того, вы нигде не принимаете во внимание исключения (а те, которые вы сами бросаете, не выдают правильно). Когда вы выделяете память, вы никак не защищаете ее, чтобы освободить ее, если возникнет непредвиденное исключение.
С учетом всего вышесказанного, попробуйте что-то более похожее на это (примечание: этот код предназначен для компиляторов с поддержкой C ++ Builder C ++ 11 - если вы используете один из «классических» пред-C ++ 11 компиляторы, вам придется соответствующим образом изменить этот код):
//---------------------------------------------------------------------------
#ifndef JSONH
#define JSONH
#include <System.Classes.hpp>
#include <System.StrUtils.hpp>
#include <System.JSON.Readers.hpp>
#include <System.JSON.Types.hpp>
#include <System.JSON.Utils.hpp>
#include <System.JSON.Writers.hpp>
#include <System.JSON.Builders.hpp>
#include <stack>
#include <fstream>
#include <utility>
#include <iostream>
#include <memory>
class JSON
{
public:
// JSON types
enum Type
{
Integer,
Boolean,
Float,
String,
Object,
Array,
Null
};
using UniquePtr = std::unique_ptr<JSON>;
using SharedPtr = std::shared_ptr<JSON>;
using Pair = std::pair<UnicodeString, SharedPtr>;
using objectStack = std::stack<Pair>;
using arrayStack = std::stack<SharedPtr>;
// Static functions
static UniquePtr JSON::parse(const UnicodeString &str);
static UniquePtr JSON::parser(TJsonTextReader& json_reader);
JSON();
explicit JSON(int val);
explicit JSON(bool val);
explicit JSON(float val);
explicit JSON(const UnicodeString &val);
explicit JSON(objectStack &val);
explicit JSON(arrayStack &val);
// Member attributes
Type type;
int int_val;
bool bool_val;
float float_val;
UnicodeString string_val;
objectStack object_val;
arrayStack array_val;
// Member functions
UniquePtr copy() const;
SharedPtr find(const UnicodeString &path) const;
UniquePtr map(const UnicodeString &key) const;
JSON * set(const UnicodeString &prop, SharedPtr value);
JSON * push(SharedPtr value);
UniquePtr filter(const JSON ¶ms) const;
SharedPtr find_by(const JSON ¶ms) const;
UnicodeString dump() const;
UnicodeString stringify() const;
int size() const;
};
//------------------------------------------------------
#endif
#pragma hdrstop
#include "JSON.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
JSON::JSON()
{
type = JSON::Null;
}
JSON::JSON(int val)
{
type = JSON::Integer;
int_val = val;
}
JSON::JSON(bool val)
{
type = JSON::Boolean;
bool_val = val;
}
JSON::JSON(float val)
{
type = JSON::Float;
float_val = val;
}
JSON::JSON(const UnicodeString &val)
{
type = JSON::String;
string_val = val;
}
JSON::JSON(JSON::objectStack &val)
{
type = JSON::Object;
object_val = val;
}
JSON::JSON(JSON::arrayStack &val)
{
type = JSON::Array;
array_val = val;
}
JSON:::UniquePtr JSON::parse(const UnicodeString &str)
{
if (str.IsEmpty())
throw Exception(_D("invalid JSON: ") + str));
std::unique_ptr<TStringReader> string_reader(new TStringReader(str));
std::unique_ptr<TJsonTextReader> json_reader(new TJsonTextReader(string_reader.get()));
return JSON::parser(*json_reader);
}
JSON::UniquePtr JSON::parser(TJsonTextReader &json_reader)
{
switch (json_reader.TokenType)
{
case TJsonToken::None:
json_reader.Read();
return JSON::parser(json_reader);
//INTEGER
case TJsonToken::Integer:
return new JSON(json_reader.Value.AsInteger());
//FLOAT
case TJsonToken::Float:
return new JSON(json_reader.Value.AsExtended());
//STRING
case TJsonToken::String:
return new JSON(json_reader.Value.AsString());
//BOOLEAN
case TJsonToken::Boolean:
return new JSON(json_reader.Value.AsBoolean());
// OBJECT
case TJsonToken::StartObject:
{
objectStack values;
while (json_reader.Read() && json_reader.TokenType != TJsonToken::EndObject)
{
UnicodeString key = json_reader.Value.AsString();
json_reader.Read();
JSON::SharedPtr val = JSON::parser(json_reader);
values.push(std::make_pair(key, val));
}
return new JSON(values);
}
// ARRAY
case TJsonToken::StartArray:
{
arrayStack values;
while (json_reader.Read() && json_reader.TokenType != TJsonToken::EndArray)
{
JSON::SharedPtr val = JSON::parser(json_reader);
values.push(val);
}
return new JSON(values);
}
//NULL
case TJsonToken::Null:
case TJsonToken::Undefined:
return new JSON;
}
return nullptr;
}
JSON::SharedPtr JSON::find(const UnicodeString &path) const
{
if ((type == JSON::Object) || (type == JSON::Array))
{
TStringDynArray slice = SplitString(path, _D("."));
if (type == JSON::Object)
{
for (std::size_t i = 0; i < object_val.size(); ++i)
{
const JSON::Pair &p = json.object_val.c[i];
if (p.first == slice[0])
{
if (slice.Length > 1)
{
UnicodeString next = slice[1];
for (int i = 2; i < slice.Length; ++i)
next += ("." + slice[i]);
return p.second->find(next);
}
else
return p.second;
}
}
}
else
{
int i;
if (TryStrToInt(slice[0], i))
{
JSON::SharedPtr &val = array_val.c[i];
if (slice.Length > 1)
{
UnicodeString next = slice[1];
for (i = 2; i < slice.Length; ++i)
next += (_D(".") + slice[i]);
return val->find(next);
}
else
return val;
}
}
}
return nullptr;
}
static UnicodeString stringify(const UnicodeString &string_val)
{
return _D("\"") + string_val + _D("\""); // TODO: escape reserved characters!
}
static UnicodeString stringify(const JSON::Pair &p)
{
return stringify(p.first) + _D(":") + p.second->stringify();
}
UnicodeString JSON::stringify() const
{
switch (type)
{
//INTEGER
case JSON::Integer:
return int_val;
//FLOAT
case JSON::Float:
{
TFormatSettings fmt = TFormatSettings::Create();
fmt.DecimalSeparator = _D('.');
fmt.ThousandDecimalSeparator = _D('\0');
return FloatToStr(float_val, fmt);
}
//STRING
case JSON::String:
return stringify(string_val);
//BOOLEAN
case JSON::Boolean:
return bool_val ? _D("true") : _D("false");
// OBJECT
case JSON::Object:
{
if (!object_val.empty())
{
UnicodeString str = _D("{") + stringify(object_val.c[0]);
for(std::size_t i = 1; i < object_val.size(); ++i)
str += (_D(", ") + stringify(object_val.c[i]));
str += _D("}");
return str;
}
else
return _D("{}");
}
// ARRAY
case JSON::Array:
{
if (!array_val.empty())
{
UnicodeString str = _D("[") + array_val.c[0]->stringify();
for (std::size_t i = 1; i < array_val.size(); ++i)
str += (_D(", ") + array_val.c[i]->stringify());
str += _D("]");
return str;
}
else
return _D("[]");
}
//NULL
case JSON::Null:
return _D("null");
}
return _D("");
}
UnicodeString JSON::dump() const
{
UnicodeString d = stringify();
return StringReplace(d, _D("\""), _D(""), TReplaceFlags() << rfReplaceAll);
}
JSON::UniquePtr JSON::map(const UnicodeString &key) const
{
if (type != JSON::Array)
throw Exception(_D("Not an array"));
arrayStack values;
for (std::size_t i = 0; i < array_val.size(); ++i)
{
JSON::SharedPtr val = array_val.c[i];
if (val->type != JSON::Object)
throw Exception(_D("Not an array of objects"));
JSON::SharedPtr j = val->find(key);
if (j)
values.push(j->copy());
}
return new JSON(values);
}
int JSON::size() const
{
switch (type)
{
case JSON::Object:
return static_cast<int>(object_val.size());
case JSON::Array:
return static_cast<int>(array_val.size());
case JSON::String:
return string_val.Length();
}
return 0;
}
JSON * JSON::set(const UnicodeString &prop, JSON::SharedPtr value)
{
if (type != JSON::Object)
throw Exception(_D("This is not an object"));
for (std::size_t i = 0; i < object_val.size(); ++i)
{
JSON::Pair &p = json.object_val.c[i];
if (p.first == prop)
{
p.second = value;
return this;
}
}
object_val.push(std::make_pair(prop, value));
return this;
}
JSON * JSON::push(JSON::SharedPtr value)
{
if (type != JSON::Array)
throw Exception(_D("This is not an array"));
array_val.push(value);
return this;
}
JSON::UniquePtr JSON::copy() const
{
switch (type)
{
//INTEGER
case JSON::Integer:
return new JSON(int_val);
//FLOAT
case JSON::Float:
return new JSON(float_val);
//STRING
case JSON::String:
return new JSON(string_val);
//BOOLEAN
case JSON::Boolean:
return new JSON(bool_val);
// OBJECT
case JSON::Object:
{
objectStack values;
for (std::size_t i = 0; i < object_val.size(); ++i)
{
UnicodeString key = object_val.c[i].first;
JSON::SharedPtr val = object_val.c[i].second->copy();
values.push(std::make_pair(key, val));
}
return new JSON(values);
}
// ARRAY
case JSON::Array:
{
arrayStack values;
for (std::size_t i = 0; i < array_val.size(); ++i)
{
JSON::SharedPtr val = array_val.c[i]->copy();
values.push(val);
}
return new JSON(values);
}
//NULL
case JSON::Null:
return new JSON;
}
return nullptr;
}
JSON::UniquePtr JSON::filter(const JSON ¶ms)
{
if (type != JSON::Array)
throw Exception(_D("this is not an array"));
if (params.type != JSON::Object)
throw Exception(_D("params is not an object"));
arrayStack values;
for (std::size_t i = 0; i < array_val.size(); ++i)
{
JSON::SharedPtr &val = array_val.c[i];
for (std::size_t it = 0; it < params.size(); ++it)
{
JSON::SharedPtr this_value = val->find(params.object_val.c[it].first);
/*
UnicodeString str_params = params.stringify();
UnicodeString str_this = stringify();
UnicodeString key_test = params.object_val.c[it].first;
UnicodeString this_test = this_value->stringify();
UnicodeString params_test = params.object_val.c[it].second->stringify();
/*
if (this_value)
{
if (this_value->stringify() == params.object_val.c[it].second->stringify())
values.push(val);
}
}
}
return new JSON(values);
}
JSON::SharedPtr JSON::find_by(const JSON ¶ms)
{
JSON::UniquePtr filtered = filter(params);
if (filtered->size())
return filtered->find(_D("0"));
return nullptr;
}