这个递归 class 需要自定义析构函数?
This recursive class needs a custom destructor?
我发现了内存泄漏问题 JSON class。
我已经很关心在使用后删除所有可能的实例,但我认为删除运算符不能删除 'object_val' 和 'array_val' 的子结构。
这有意义吗?我怎样才能'recursevly'删除de结构?
//---------------------------------------------------------------------------
#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.h>
#include <utility>
#include <iostream>
class JSON;
class JSON {
public:
// JSON types
enum Type {
__INT,
__BOOLEAN,
__FLOAT,
__STRING,
__OBJECT,
__ARRAY,
__NULL
};
// Static functions
static JSON * JSON::parse(UnicodeString str);
static JSON & JSON::parser(TJsonTextReader& json_reader);
static bool JSON::isNumber(const std::string& s);
JSON(){}
~JSON(){}
// Member attributtes
Type type;
int int_val;
bool bool_val;
float float_val;
UnicodeString string_val;
stack<pair<UnicodeString, JSON*> > *object_val;
stack<JSON*> *array_val;
// Member functions
JSON * copy();
JSON * find(UnicodeString path);
JSON * map(UnicodeString key);
JSON * set(UnicodeString prop, JSON *value);
JSON * push(JSON *value);
JSON * filter(JSON *params);
JSON * find_by(JSON *params);
UnicodeString dump();
UnicodeString stringify();
int size();
};
//------------------------------------------------------
#endif
#pragma hdrstop
#include "JSON.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
using namespace std;
JSON * JSON::parse(UnicodeString str){
if (str == "") {
throw "invalid JSON: " + str;
}
TStringReader *string_reader = new TStringReader(str);
TJsonTextReader *json_reader = new TJsonTextReader(string_reader);
JSON *result = new JSON;
*result = JSON::parser(*json_reader);
delete string_reader;
delete json_reader;
return result;
}
JSON & JSON::parser(TJsonTextReader &json_reader){
if(json_reader.TokenType == TJsonToken::None){
json_reader.Read();
return JSON::parser(json_reader);
}
JSON *json = new JSON;
//INTEGER
if(json_reader.TokenType == TJsonToken::Integer){
json->type = JSON::__INT;
json->int_val = json_reader.Value.AsInteger();
return *json;
}
//FLOAT
else if(json_reader.TokenType == TJsonToken::Float){
json->type = JSON::__FLOAT;
json->float_val = json_reader.Value.AsExtended();
return *json;
}
//STRING
else if(json_reader.TokenType == TJsonToken::String){
json->type = JSON::__STRING;
json->string_val = json_reader.Value.AsString();
return *json;
}
//BOOLEAN
else if(json_reader.TokenType == TJsonToken::Boolean){
json->type = JSON::__BOOLEAN;
json->bool_val = json_reader.Value.AsBoolean();
return *json;
}
// OBJECT
else if(json_reader.TokenType == TJsonToken::StartObject){
json->type = JSON::__OBJECT;
json->object_val = new stack<pair<UnicodeString, JSON*> >;
while(json_reader.Read() && json_reader.TokenType != TJsonToken::EndObject){
UnicodeString key = json_reader.Value.AsString();
json_reader.Read();
JSON *val = new JSON;
*val = JSON::parser(json_reader);
json->object_val->push(make_pair(key, val));
}
return *json;
}
// ARRAY
else if(json_reader.TokenType == TJsonToken::StartArray){
json->type = JSON::__ARRAY;
json->array_val = new stack<JSON*>;
while(json_reader.Read() && json_reader.TokenType != TJsonToken::EndArray){
JSON *val = new JSON;
*val = JSON::parser(json_reader);
json->array_val->push(val);
}
return *json;
}
//NULL
else if(
json_reader.TokenType == TJsonToken::Null
|| json_reader.TokenType == TJsonToken::Undefined
){
json->type = JSON::__NULL;
return *json;
}
}
bool JSON::isNumber(const std::string& s) {
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
JSON * JSON::find(UnicodeString path){
TStringDynArray slice = SplitString(path, ".");
UnicodeString next = "";
if(slice.Length > 1){
for (int i = 1; i < slice.Length; ++i) {
next += slice[i];
if (i != slice.Length-1) {
next += ".";
}
}
}
if (type == __OBJECT){
for (int i = 0; i < object_val->size(); i++) {
if (object_val->c[i].first == slice[0]){
if (slice.Length > 1) {
return object_val->c[i].second->find(next);
}
else {
return object_val->c[i].second;
}
}
}
}
else if(type == __ARRAY){
wstring ws(slice[0].c_str());
string str(ws.begin(), ws.end());
if (JSON::isNumber(str)){
if (slice.Length > 1) {
return array_val->c[slice[0].ToInt()]->find(next);
}
else {
return array_val->c[slice[0].ToInt()];
}
}
}
return NULL;
}
UnicodeString JSON::stringify(){
//INTEGER
if(type == JSON::__INT){
return (UnicodeString) int_val;
}
//FLOAT
else if(type == JSON::__FLOAT){
return (UnicodeString) float_val;
}
//STRING
else if(type == JSON::__STRING){
return (UnicodeString) "\""+ string_val + "\"";
}
//BOOLEAN
else if(type == JSON::__BOOLEAN){
if(bool_val){
return (UnicodeString) "true";
}
else {
return (UnicodeString) "false";
}
}
// OBJECT
else if(type == JSON::__OBJECT){
if (object_val->size()){
UnicodeString str = "{";
for (int i = 0; i < object_val->size(); ++i){
str += "\"" + object_val->c[i].first + "\":" + object_val->c[i].second->stringify();
if (object_val->size()-1 != i){
str += ", ";
}
}
str += "}";
return str;
}
else {
return (UnicodeString) "{}";
}
}
// ARRAY
else if(type == JSON::__ARRAY){
if (array_val->size()){
UnicodeString str = "[";
for (int i = 0; i < array_val->size(); ++i){
str += array_val->c[i]->stringify();
if (array_val->size()-1 != i){
str += ", ";
}
}
str += "]";
return str;
}
else {
return (UnicodeString) "[]";
}
}
//NULL
else if(type == JSON::__NULL){
return (UnicodeString) "null";
}
}
UnicodeString JSON::dump(){
UnicodeString d = stringify();
return StringReplace(d, "\"", "", TReplaceFlags() << rfReplaceAll);
}
JSON * JSON::map(UnicodeString key){
if (type != JSON::__ARRAY){
throw "Not a array";
}
UnicodeString str_result = "[";
for (int i = 0; i < array_val->size(); ++i){
JSON *val = array_val->c[i];
if(val->type != JSON::__OBJECT){
throw "Not a array of objects";
}
else {
str_result += val->find(key)->stringify();
}
if(i != array_val->size()-1){
str_result += ',';
}
}
str_result += "]";
return JSON::parse(str_result);
}
int JSON::size(){
if(type == JSON::__OBJECT){
return object_val->size();
}
else if (type == JSON::__ARRAY){
return array_val->size();
}
else if (type == JSON::__STRING){
return string_val.Length();
}
else {
return 0;
}
}
JSON * JSON::set(UnicodeString prop, JSON *value){
if (this->type == JSON::__OBJECT) {
this->object_val->push(make_pair(prop, value));
}
else {
throw "This is not an object";
}
return this;
}
JSON * JSON::push(JSON *value){
if (this->type == JSON::__ARRAY) {
this->array_val->push(value);
}
else {
throw "This is not an array";
}
return this;
}
JSON * JSON::copy(){
JSON *copy;
if(type == JSON::__ARRAY){
copy = JSON::parse("[]");
for (int i = 0; i < size(); ++i){
copy->push(array_val->c[i]->copy());
}
}
if(type == JSON::__OBJECT){
copy = JSON::parse("{}");
for (int i = 0; i < size(); ++i){
UnicodeString key = this->object_val->c[i].first;
JSON *val = this->object_val->c[i].second->copy();
copy->set(key, val);
}
}
else{
copy = JSON::parse(this->stringify());
}
return copy;
}
JSON * JSON::filter(JSON *params){
if(type != JSON::__ARRAY)
throw "this is not an array";
if (params->type != JSON::__OBJECT)
throw "params is not an object";
JSON *result = JSON::parse("[]");
JSON *this_value;
for (int i = 0; i < this->array_val->size(); ++i){
for (int it = 0; it < params->size(); ++it){
this_value = this->array_val->c[i]->find(params->object_val->c[it].first);
UnicodeString str_params = params->stringify();
UnicodeString str_this = 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 != NULL){
if(this_value->stringify() == params->object_val->c[it].second->stringify()){
result->array_val->push(this->array_val->c[i]);
}
}
}
}
return result;
}
JSON * JSON::find_by(JSON *params){
JSON *filtered = filter(params);
if(filtered->size()){
return filtered->find("0");
}
return NULL;
}
我可以保证删除应用程序上的每个 JSON 对象。它只用了两次 JSON::parse(UnicodeString(request)).
更新:
使用以下析构函数解决:
~JSON(){
if (type == JSON::__OBJECT) {
for (int i = 0; i < object_val->size(); ++i)
if(object_val->c[i].second)
delete object_val->c[i].second;
delete object_val;
}
if(type == JSON::__ARRAY){
for (int i = 0; i < array_val->size(); ++i)
if(array_val->c[i])
delete array_val->c[i];
delete array_val;
}
}
C/C++中有一个简单的设计规则:分配者必须释放。
这在 99% 的情况下都是有效的。如果您认为您应该以其他方式设计它,请再考虑一下。
与该规则相符的检查是您必须拥有与 delete
一样多的 new
。在您的示例中,您有 8 new
、2 delete
。 (它也适用于 malloc
/free
的 C 语言)。
确实,更好的析构函数应该有用。
如果您仍然有内存泄漏,请查看 valgrind 工具,它可以帮助您定位内存泄漏。您可以检查智能指针以避免管理内存的一些麻烦
欢迎来到 Stack Overflow =)
您的代码中存在许多漏洞。
您的 parser()
方法 returns 一个 JSON&
引用而不是 JSON*
指针(就像您的 parse()
方法一样)。您正在通过 new
分配一个新的 JSON
对象,然后通过取消引用指针将其返回给调用者,然后调用者 将该对象复制 到 another 分配了 JSON
对象(但你没有实现正确的复制赋值运算符!)并且没有 delete
原始对象。你在 parse()
和 parser()
.
中多次犯了这个错误
您的 find_by()
方法中也有类似的内存泄漏。您的 filter()
方法 returns 一个指向 new
的 JSON
对象的 JSON*
指针,但是 find_by()
不是 delete
的使用完该对象后。
此外,当 parser()
遇到 StartObject
或 StartArray
标记时,它 new
是一个永远不会 delete
的 std::stack
对象'd 当分配给它的 JSON
对象被销毁时。您需要向 JSON
class 添加析构函数以释放那些 std::stack
对象,以及它们持有指向的 JSON
对象。
但是你 运行 陷入另一个问题,因为如果调用 filter()
这样的析构函数将会中断,因为它 returns a new
' JSON
对象,它包含指向另一个 JSON
对象所拥有的值的指针。当 delete
'ing 过滤后的 JSON
对象时,这些值将被破坏,从而破坏正在过滤的原始 JSON
对象。
此外,您没有在任何地方考虑异常(并且您抛出的异常没有被正确抛出)。当您分配内存时,您不会以任何方式保护它,以便在抛出意外异常时可以释放它。
综上所述,尝试更像这样的东西(注意:此代码适用于 C++Builder 的支持 C++11 的编译器 - 如果您使用的是 "classic" 预编译器之一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('[=11=]');
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;
}
我发现了内存泄漏问题 JSON class。
我已经很关心在使用后删除所有可能的实例,但我认为删除运算符不能删除 'object_val' 和 'array_val' 的子结构。
这有意义吗?我怎样才能'recursevly'删除de结构?
//---------------------------------------------------------------------------
#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.h>
#include <utility>
#include <iostream>
class JSON;
class JSON {
public:
// JSON types
enum Type {
__INT,
__BOOLEAN,
__FLOAT,
__STRING,
__OBJECT,
__ARRAY,
__NULL
};
// Static functions
static JSON * JSON::parse(UnicodeString str);
static JSON & JSON::parser(TJsonTextReader& json_reader);
static bool JSON::isNumber(const std::string& s);
JSON(){}
~JSON(){}
// Member attributtes
Type type;
int int_val;
bool bool_val;
float float_val;
UnicodeString string_val;
stack<pair<UnicodeString, JSON*> > *object_val;
stack<JSON*> *array_val;
// Member functions
JSON * copy();
JSON * find(UnicodeString path);
JSON * map(UnicodeString key);
JSON * set(UnicodeString prop, JSON *value);
JSON * push(JSON *value);
JSON * filter(JSON *params);
JSON * find_by(JSON *params);
UnicodeString dump();
UnicodeString stringify();
int size();
};
//------------------------------------------------------
#endif
#pragma hdrstop
#include "JSON.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
using namespace std;
JSON * JSON::parse(UnicodeString str){
if (str == "") {
throw "invalid JSON: " + str;
}
TStringReader *string_reader = new TStringReader(str);
TJsonTextReader *json_reader = new TJsonTextReader(string_reader);
JSON *result = new JSON;
*result = JSON::parser(*json_reader);
delete string_reader;
delete json_reader;
return result;
}
JSON & JSON::parser(TJsonTextReader &json_reader){
if(json_reader.TokenType == TJsonToken::None){
json_reader.Read();
return JSON::parser(json_reader);
}
JSON *json = new JSON;
//INTEGER
if(json_reader.TokenType == TJsonToken::Integer){
json->type = JSON::__INT;
json->int_val = json_reader.Value.AsInteger();
return *json;
}
//FLOAT
else if(json_reader.TokenType == TJsonToken::Float){
json->type = JSON::__FLOAT;
json->float_val = json_reader.Value.AsExtended();
return *json;
}
//STRING
else if(json_reader.TokenType == TJsonToken::String){
json->type = JSON::__STRING;
json->string_val = json_reader.Value.AsString();
return *json;
}
//BOOLEAN
else if(json_reader.TokenType == TJsonToken::Boolean){
json->type = JSON::__BOOLEAN;
json->bool_val = json_reader.Value.AsBoolean();
return *json;
}
// OBJECT
else if(json_reader.TokenType == TJsonToken::StartObject){
json->type = JSON::__OBJECT;
json->object_val = new stack<pair<UnicodeString, JSON*> >;
while(json_reader.Read() && json_reader.TokenType != TJsonToken::EndObject){
UnicodeString key = json_reader.Value.AsString();
json_reader.Read();
JSON *val = new JSON;
*val = JSON::parser(json_reader);
json->object_val->push(make_pair(key, val));
}
return *json;
}
// ARRAY
else if(json_reader.TokenType == TJsonToken::StartArray){
json->type = JSON::__ARRAY;
json->array_val = new stack<JSON*>;
while(json_reader.Read() && json_reader.TokenType != TJsonToken::EndArray){
JSON *val = new JSON;
*val = JSON::parser(json_reader);
json->array_val->push(val);
}
return *json;
}
//NULL
else if(
json_reader.TokenType == TJsonToken::Null
|| json_reader.TokenType == TJsonToken::Undefined
){
json->type = JSON::__NULL;
return *json;
}
}
bool JSON::isNumber(const std::string& s) {
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
JSON * JSON::find(UnicodeString path){
TStringDynArray slice = SplitString(path, ".");
UnicodeString next = "";
if(slice.Length > 1){
for (int i = 1; i < slice.Length; ++i) {
next += slice[i];
if (i != slice.Length-1) {
next += ".";
}
}
}
if (type == __OBJECT){
for (int i = 0; i < object_val->size(); i++) {
if (object_val->c[i].first == slice[0]){
if (slice.Length > 1) {
return object_val->c[i].second->find(next);
}
else {
return object_val->c[i].second;
}
}
}
}
else if(type == __ARRAY){
wstring ws(slice[0].c_str());
string str(ws.begin(), ws.end());
if (JSON::isNumber(str)){
if (slice.Length > 1) {
return array_val->c[slice[0].ToInt()]->find(next);
}
else {
return array_val->c[slice[0].ToInt()];
}
}
}
return NULL;
}
UnicodeString JSON::stringify(){
//INTEGER
if(type == JSON::__INT){
return (UnicodeString) int_val;
}
//FLOAT
else if(type == JSON::__FLOAT){
return (UnicodeString) float_val;
}
//STRING
else if(type == JSON::__STRING){
return (UnicodeString) "\""+ string_val + "\"";
}
//BOOLEAN
else if(type == JSON::__BOOLEAN){
if(bool_val){
return (UnicodeString) "true";
}
else {
return (UnicodeString) "false";
}
}
// OBJECT
else if(type == JSON::__OBJECT){
if (object_val->size()){
UnicodeString str = "{";
for (int i = 0; i < object_val->size(); ++i){
str += "\"" + object_val->c[i].first + "\":" + object_val->c[i].second->stringify();
if (object_val->size()-1 != i){
str += ", ";
}
}
str += "}";
return str;
}
else {
return (UnicodeString) "{}";
}
}
// ARRAY
else if(type == JSON::__ARRAY){
if (array_val->size()){
UnicodeString str = "[";
for (int i = 0; i < array_val->size(); ++i){
str += array_val->c[i]->stringify();
if (array_val->size()-1 != i){
str += ", ";
}
}
str += "]";
return str;
}
else {
return (UnicodeString) "[]";
}
}
//NULL
else if(type == JSON::__NULL){
return (UnicodeString) "null";
}
}
UnicodeString JSON::dump(){
UnicodeString d = stringify();
return StringReplace(d, "\"", "", TReplaceFlags() << rfReplaceAll);
}
JSON * JSON::map(UnicodeString key){
if (type != JSON::__ARRAY){
throw "Not a array";
}
UnicodeString str_result = "[";
for (int i = 0; i < array_val->size(); ++i){
JSON *val = array_val->c[i];
if(val->type != JSON::__OBJECT){
throw "Not a array of objects";
}
else {
str_result += val->find(key)->stringify();
}
if(i != array_val->size()-1){
str_result += ',';
}
}
str_result += "]";
return JSON::parse(str_result);
}
int JSON::size(){
if(type == JSON::__OBJECT){
return object_val->size();
}
else if (type == JSON::__ARRAY){
return array_val->size();
}
else if (type == JSON::__STRING){
return string_val.Length();
}
else {
return 0;
}
}
JSON * JSON::set(UnicodeString prop, JSON *value){
if (this->type == JSON::__OBJECT) {
this->object_val->push(make_pair(prop, value));
}
else {
throw "This is not an object";
}
return this;
}
JSON * JSON::push(JSON *value){
if (this->type == JSON::__ARRAY) {
this->array_val->push(value);
}
else {
throw "This is not an array";
}
return this;
}
JSON * JSON::copy(){
JSON *copy;
if(type == JSON::__ARRAY){
copy = JSON::parse("[]");
for (int i = 0; i < size(); ++i){
copy->push(array_val->c[i]->copy());
}
}
if(type == JSON::__OBJECT){
copy = JSON::parse("{}");
for (int i = 0; i < size(); ++i){
UnicodeString key = this->object_val->c[i].first;
JSON *val = this->object_val->c[i].second->copy();
copy->set(key, val);
}
}
else{
copy = JSON::parse(this->stringify());
}
return copy;
}
JSON * JSON::filter(JSON *params){
if(type != JSON::__ARRAY)
throw "this is not an array";
if (params->type != JSON::__OBJECT)
throw "params is not an object";
JSON *result = JSON::parse("[]");
JSON *this_value;
for (int i = 0; i < this->array_val->size(); ++i){
for (int it = 0; it < params->size(); ++it){
this_value = this->array_val->c[i]->find(params->object_val->c[it].first);
UnicodeString str_params = params->stringify();
UnicodeString str_this = 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 != NULL){
if(this_value->stringify() == params->object_val->c[it].second->stringify()){
result->array_val->push(this->array_val->c[i]);
}
}
}
}
return result;
}
JSON * JSON::find_by(JSON *params){
JSON *filtered = filter(params);
if(filtered->size()){
return filtered->find("0");
}
return NULL;
}
我可以保证删除应用程序上的每个 JSON 对象。它只用了两次 JSON::parse(UnicodeString(request)).
更新: 使用以下析构函数解决:
~JSON(){
if (type == JSON::__OBJECT) {
for (int i = 0; i < object_val->size(); ++i)
if(object_val->c[i].second)
delete object_val->c[i].second;
delete object_val;
}
if(type == JSON::__ARRAY){
for (int i = 0; i < array_val->size(); ++i)
if(array_val->c[i])
delete array_val->c[i];
delete array_val;
}
}
C/C++中有一个简单的设计规则:分配者必须释放。
这在 99% 的情况下都是有效的。如果您认为您应该以其他方式设计它,请再考虑一下。
与该规则相符的检查是您必须拥有与 delete
一样多的 new
。在您的示例中,您有 8 new
、2 delete
。 (它也适用于 malloc
/free
的 C 语言)。
确实,更好的析构函数应该有用。
如果您仍然有内存泄漏,请查看 valgrind 工具,它可以帮助您定位内存泄漏。您可以检查智能指针以避免管理内存的一些麻烦
欢迎来到 Stack Overflow =)
您的代码中存在许多漏洞。
您的 parser()
方法 returns 一个 JSON&
引用而不是 JSON*
指针(就像您的 parse()
方法一样)。您正在通过 new
分配一个新的 JSON
对象,然后通过取消引用指针将其返回给调用者,然后调用者 将该对象复制 到 another 分配了 JSON
对象(但你没有实现正确的复制赋值运算符!)并且没有 delete
原始对象。你在 parse()
和 parser()
.
您的 find_by()
方法中也有类似的内存泄漏。您的 filter()
方法 returns 一个指向 new
的 JSON
对象的 JSON*
指针,但是 find_by()
不是 delete
的使用完该对象后。
此外,当 parser()
遇到 StartObject
或 StartArray
标记时,它 new
是一个永远不会 delete
的 std::stack
对象'd 当分配给它的 JSON
对象被销毁时。您需要向 JSON
class 添加析构函数以释放那些 std::stack
对象,以及它们持有指向的 JSON
对象。
但是你 运行 陷入另一个问题,因为如果调用 filter()
这样的析构函数将会中断,因为它 returns a new
' JSON
对象,它包含指向另一个 JSON
对象所拥有的值的指针。当 delete
'ing 过滤后的 JSON
对象时,这些值将被破坏,从而破坏正在过滤的原始 JSON
对象。
此外,您没有在任何地方考虑异常(并且您抛出的异常没有被正确抛出)。当您分配内存时,您不会以任何方式保护它,以便在抛出意外异常时可以释放它。
综上所述,尝试更像这样的东西(注意:此代码适用于 C++Builder 的支持 C++11 的编译器 - 如果您使用的是 "classic" 预编译器之一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('[=11=]');
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;
}