I am parsing files that have a structure similar to JSON, where I have objects equivalent to Int
, String
, List
(of objects) and Dictionary
(keys are strings and values are objects), among others. In particular, I end up with nested lists and dictionaries.
The below code is allowing me to store the parsed data and sometimes retrieve it. I can retrieve nested lists (implemented as std::vector<Object>
) without any problem, and I can retrieve dictionaries (implemented as std::map<std::string, Object>
) if not nested in other dictionaries. When I have nested dictionaries, I sometimes end up with segmentation fault
. On some occasion, it seems that the loop does not halt after reading the map's entries.
The below three files should allow to reproduce the problem.
I am mainly interested in understanding what is going wrong, rather than only having something that works.
- In the function
std::ostream &operator<<(std::ostream &Stream, const ObjDictionry &Dictionry);
iterating using for(auto Pair: Dictionry)
seems to produce the problem more often than for(auto it=Dictionry.begin();it!=Dictionry.end();++it)
, and I would like to understand why they behave differently.
-
In the file
test.cc
,Other
is printed ok on its own, andObj
also printes ok if you change the code, for example, toObj["3"]["Key"]=Value;
. I would like to understand what is the issue with the current example. -
While trying to solve the problem, I have printer the address to map iterator
it
, it seems that it does not equalDictionary.end()
when it exhausts the map entries, and I would like to understand what is wrong with the code to result in this behaviour.
I would be grateful for answers and hints.
types.h
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#include <vector>
struct Object;
enum Tags {
DTInt,
DTKey,
DTList,
DTDictionry,
};
typedef int ObjInt;
typedef std::string ObjKey;
typedef std::vector<Object> ObjList;
typedef std::map<ObjKey, Object> ObjDictionry;
union ObjData {
ObjInt Int;
ObjKey Key;
ObjList List;
ObjDictionry Dictionry;
ObjData();
~ObjData();
ObjData &operator=(const ObjData &Other);
};
struct Object {
Tags Tag;
ObjData Data;
Object();
Object(Tags Tag, ObjData Data) {}
Object(const Object &Other);
Object &operator=(const Object &Other);
Object &operator=(const int &Other);
Object &operator=(const std::string &Other);
Object &operator=(const std::map<ObjKey, Object> &Other);
Object &operator=(const std::vector<Object> &Other);
Object &operator[](const std::string &Key);
};
extern std::ostream &operator<<(std::ostream &Stream, const Object &Obj);
extern std::ostream &operator<<(std::ostream &Stream, const ObjList &List);
extern std::ostream &operator<<(std::ostream &Stream,
const ObjDictionry &Dictionry);
types.cc
#include "types.h"
// Constructing the member of the biggest size
ObjData::ObjData() : Dictionry{} {};
// ObjData::ObjData() { memset(this, 0, sizeof(ObjData)); }
ObjData::~ObjData() {}
ObjData &ObjData::operator=(const ObjData &Other) {
// FIXME: Shalow/Deep copy
memcpy(this, &Other, sizeof(ObjData));
return *this;
}
Object::Object() : Tag{}, Data{} {};
Object::Object(const Object &Other) {
Tag = Other.Tag;
Data = Other.Data;
}
Object &Object::operator=(const Object &Other) {
Tag = Other.Tag;
Data = Other.Data;
return *this;
}
Object &Object::operator=(const int &Other) {
Tag = DTInt;
Data.Int = Other;
return *this;
}
Object &Object::operator=(const std::string &Other) {
Tag = DTKey;
Data.Key = Other;
return *this;
}
Object &Object::operator=(const std::map<ObjKey, Object> &Other) {
Tag = DTDictionry;
Data.Dictionry = Other;
return *this;
}
Object &Object::operator=(const std::vector<Object> &Other) {
Tag = DTList;
Data.List = Other;
return *this;
}
Object &Object::operator[](const std::string &Key) {
try {
if (Tag != DTDictionry)
throw(Tag);
return Data.Dictionry[Key];
} catch (int T) {
std::cerr << "Object operator[] is called with the wrong tag `" << (int)Tag
<< "`\n";
}
// TODO decide what to return, the below return is temporarily to suppress the
// warning
return *this;
};
std::ostream &operator<<(std::ostream &Stream, const Object &Obj) {
// TODO use it to create toJSON method
switch (Obj.Tag) {
case DTInt:
Stream << Obj.Data.Int;
break;
case DTKey:
Stream << Obj.Data.Key;
break;
case DTList:
Stream << Obj.Data.List;
break;
case DTDictionry:
Stream << Obj.Data.Dictionry;
break;
default:
std::cerr << "Undefined `Obj.Tag=" << (int)Obj.Tag << "`.\n";
}
return Stream;
};
std::ostream &operator<<(std::ostream &Stream, const ObjList &List) {
Stream << "[\n";
for (Object Obj : List)
Stream << Obj << ", \n";
Stream << "]\n";
return Stream;
};
std::ostream &operator<<(std::ostream &Stream, const ObjDictionry &Dictionry) {
Stream << "{\n";
// for (std::pair<ObjKey, Object> Pair : Dictionry) {
// Stream << Pair.first << ": " << Pair.second << ", \n";
// }
for (ObjDictionry::const_iterator it = Dictionry.begin();
it != Dictionry.end(); ++it) {
Stream << it->first << ": " << it->second << ", \n";
}
Stream << "}\n";
return Stream;
};
test.cc
#include "types.h"
int main(int argc, char const *argv[]) {
Object Obj{};
Obj = ObjDictionry{};
Obj["1"] = 1;
Obj["2"] = ObjList{};
Object Value{};
Value = std::string("text");
Obj["2"].Data.List.push_back(Value);
Obj["2"].Data.List.push_back(Value);
Obj["3"] = ObjDictionry{};
Object Other{};
Other = ObjDictionry{};
Other["1"] = 1;
Obj["3"]["Key"] = Other;
std::cout << Other << '\n';
std::cout << Obj << '\n';
return 0;
}
I usually compile using Clang++, but g++ reproduces the problem.
clang++ test.cc types.cc -o test.o && ./test.o
Aucun commentaire:
Enregistrer un commentaire