Неправильное заполнения rapidjson документа. Assert при попытке найти данные

есть вот такой код.

    #include <iostream>
#include <vector>
#include <rapidjson.h>
#include <document.h>
#include <writer.h>
#include <stringbuffer.h>

using namespace std;

enum AccessLvl {
    LOW = 0,
    AVERAGE = 1,
    HIGH = 2
};

class Message {
public:
    Message(std::string login,
            std::string loginColor,
            std::string imageSource,
            std::string message,
            std::string time,
            bool        firstmessage)
            : _login(login),
            _loginColor(loginColor),
            _imageSource(imageSource),
            _message(message),
            _time(time),
            _firstmessage(firstmessage){};
public:
    rapidjson::Document to_json();
private:
    std::string _login;
    std::string _loginColor;
    std::string _imageSource;
    std::string _message;
    std::string _time;
    bool        _firstmessage;
};

class Contacts {
public:
    Contacts(std::string username, std::string imageSource, std::string lastMessage, std::vector<Message> messages)
    : _username(username),
    _imageSource(imageSource),
    _lastMessage(lastMessage),
    _messages(messages) {};
public:
    rapidjson::Document to_json();

private:
    std::string _username;
    std::string _imageSource;
    std::string _lastMessage;
    std::vector<Message> _messages;
};

class PersonalData {
public:
    PersonalData(std::string name, std::string surname, std::string patronumic, std::string yearsold)
    : _name(name),
    _surname(surname),
    _patronymic(patronumic),
    _yearsold(yearsold) {};

    PersonalData(const PersonalData& pd)
    : _name(pd._name),
    _surname(pd._surname),
    _patronymic(pd._patronymic),
    _yearsold(pd._yearsold) {};


    PersonalData() {};
public:
    rapidjson::Document to_json();

public:
    std::string _name;
    std::string _surname;
    std::string _patronymic;
    std::string _yearsold;
};

class User {
public:
    User(std::string imageSource,
         std::string login,
         std::string pass,
         std::vector<Contacts> contacts,
         AccessLvl accessLvl,
         PersonalData personalData);
    User(const User &user);
    User(User &user);

public:

    rapidjson::Document to_json();
    PersonalData* get_personalData();
    AccessLvl get_access_lvl();
    std::string get_login();
    std::string get_pass();
    void show_data();
    int get_id();

private:
    int _id;
    std::string _imageSource;
    std::string _login;
    std::string _password;
    std::vector<Contacts> _contacts;
    AccessLvl _accessLvl;
    PersonalData* _personalData;
};

User::User(std::string imageSource,
           std::string login,
           std::string pass,
           std::vector<Contacts> contacts,
           AccessLvl accessLvl,
           PersonalData personalData)
{
    _imageSource = imageSource;
    _login = login;
    _password = pass;
    _accessLvl = accessLvl;
    _personalData = new PersonalData(personalData);
    _contacts = contacts;
}


User::User(User &user) {
    _login = user._login;
    _password = user._password;
    _accessLvl = user._accessLvl;
    _personalData = user._personalData;
}

User::User(const User &user) {
    _login = user._login;
    _password = user._password;
    _accessLvl = user._accessLvl;
    _personalData = user._personalData;
}

rapidjson::Document User::to_json(){
    rapidjson::Document document;
    document.SetObject();
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
    rapidjson::Value jsonUser(rapidjson::kObjectType);
    rapidjson::Value login;
    rapidjson::Value password;
    rapidjson::Value jsonContacts(rapidjson::kArrayType);
    rapidjson::Value accessLvl;
    rapidjson::Value personalData(rapidjson::kObjectType);

    for (int i = 0; i < _contacts.size(); ++i) {
        jsonContacts.PushBack(_contacts[i].to_json(),allocator);
    }

    login.SetString(_login.c_str(), _login.size(),allocator);
    password.SetString(_password.c_str(), _password.size(),allocator);
    accessLvl.SetInt64(_accessLvl);

    personalData.AddMember("personalData", _personalData->to_json(),allocator);

    jsonUser.AddMember("login", login,allocator);
    jsonUser.AddMember("password", password,allocator);
    jsonUser.AddMember("contacts", jsonContacts,allocator);
    jsonUser.AddMember("accessLvl", accessLvl,allocator);
    jsonUser.AddMember("personalData", personalData, allocator);

    document.AddMember("user", jsonUser, allocator);
    return document;
}

rapidjson::Document PersonalData::to_json() {
    rapidjson::Document document;
    document.SetObject();
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
    rapidjson::Value jsonPersonalData(rapidjson::kObjectType);
    rapidjson::Value name;
    rapidjson::Value surname;
    rapidjson::Value patronymic;
    rapidjson::Value yearsold;

    name.SetString(_name.c_str(), _name.size(),allocator);
    surname.SetString(_surname.c_str(), _surname.size(),allocator);
    patronymic.SetString(_patronymic.c_str(), _patronymic.size(),allocator);
    yearsold.SetString(_yearsold.c_str(), _yearsold.size(),allocator);

    jsonPersonalData.AddMember("name", name,allocator);
    jsonPersonalData.AddMember("surname", surname,allocator);
    jsonPersonalData.AddMember("patronymic", patronymic,allocator);
    jsonPersonalData.AddMember("yearsold", yearsold,allocator);

    document.AddMember("personalData", jsonPersonalData, allocator);
    return document;
}

rapidjson::Document Contacts::to_json() {
    rapidjson::Document document;
    document.SetObject();
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
    rapidjson::Value jsonContact(rapidjson::kObjectType);
    rapidjson::Value username;
    rapidjson::Value imageSource;
    rapidjson::Value lastMessage;
    rapidjson::Value jsonMessages(rapidjson::kArrayType);
    rapidjson::Value messages(rapidjson::kArrayType);

    for (int i = 0; i < _messages.size(); ++i) {
        messages.PushBack(_messages[i].to_json(),allocator);
    }

    username.SetString(_username.c_str(), _username.size(),allocator);
    imageSource.SetString(_imageSource.c_str(), _imageSource.size(),allocator);
    lastMessage.SetString(_lastMessage.c_str(), _lastMessage.size(),allocator);

    jsonContact.AddMember("username", username ,allocator);
    jsonContact.AddMember("image_source", imageSource,allocator);
    jsonContact.AddMember("last_message", lastMessage,allocator);
    jsonContact.AddMember("messages", messages,allocator);

    document.AddMember("contact", jsonContact, allocator);
    return document;
}

rapidjson::Document Message::to_json() {
    rapidjson::Document document;
    document.SetObject();
    rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
    rapidjson::Value jsonMessage(rapidjson::kObjectType);
    rapidjson::Value login;
    rapidjson::Value loginColor;
    rapidjson::Value imageSource;
    rapidjson::Value message;
    rapidjson::Value time;
    rapidjson::Value firstMessage;

    login.SetString(_login.c_str(), _login.size(),allocator);
    loginColor.SetString(_loginColor.c_str(), _loginColor.size(),allocator);
    imageSource.SetString(_imageSource.c_str(), _imageSource.size(),allocator);
    message.SetString(_message.c_str(), _message.size(),allocator);
    time.SetString(_time.c_str(), _time.size(),allocator);
    firstMessage.SetBool(_firstmessage);

    jsonMessage.AddMember("login", login ,allocator);
    jsonMessage.AddMember("login_color", loginColor,allocator);
    jsonMessage.AddMember("image_source", imageSource,allocator);
    jsonMessage.AddMember("message", message,allocator);
    jsonMessage.AddMember("time", time,allocator);
    jsonMessage.AddMember("firstMessage", firstMessage,allocator);

    if(document.IsObject())
        document.AddMember("message", jsonMessage, document.GetAllocator());
    else
        std::cout << "ERROR";

    return document;
}


void WriteDocumentToString(const rapidjson::Document& document, std::string& output) {
    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
    document.Accept(writer);
    output = buffer.GetString();
}

int main() {
    Message msg1("Admin", "Green", "link.com", "message bla bla bla", "11:24", true);
    Message msg2("Admin", "Green", "link.com", "message bla bla bla", "11:25", true);
    Message msg3("Admin", "Green", "link.com", "message bla bla bla", "11:26", true);

    std::vector<Message> messages;
    messages.push_back(msg1);
    messages.push_back(msg2);
    messages.push_back(msg3);

    Contacts cont1("Lexa", "image.com", "bla bla bla", messages);
    Contacts cont2("Stepan", "image.com", "bla bla bla", messages);
    Contacts cont3("Oleg", "image.com", "bla bla bla", messages);

    std::vector<Contacts> contacts;
    contacts.push_back(cont1);
    contacts.push_back(cont2);
    contacts.push_back(cont3);

    PersonalData pd("Dima","Lol","Ivanovich","13.12.1998");
    User test("image.com", "Admin", "Admin", contacts, HIGH, pd);


    std::string json;
    rapidjson::Document doc;

    try {
        WriteDocumentToString(test.to_json(), json);
    } catch (std::exception& ex) {
        std::cout << ex.what() << std::endl;
    }
    return 0;
}

Ошибка при попытке записать документ в строку

        WriteDocumentToString(test.to_json(), json);

Signal: SIGSEGV (Segmentation fault)

Ответы (1 шт):

Автор решения: lbsmart

Проблема была в аллокаторых которые уничтожались при выходе из функции. Многие примеры RapidJSON говорят вам использовать такие вызовы, как:

Document d;
doc.AddMember("txt", smth , doc.GetAllocator());

Но подход всегда использовать doc.GetAllocator() работает только для простых примеров.

Причина segfault, по-видимому, заключается в том, что как только Document объект выходит за пределы области видимости, его экземпляр распределителя освобождается, и, следовательно, память будет использоваться повторно. Решение:

#include <iostream>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/ostreamwrapper.h>

using namespace rapidjson;
using namespace std;

MemoryPoolAllocator<> jsonAlloc; // Это по сути и является решением, создание общего аллокатора

Document generateInnerDoc() {
    Document doc;
    doc.SetObject(); // Make doc an object !
    doc.AddMember("text", Value().SetString("Hello JSON!"), jsonAlloc);
    return doc;
}
Document generateOuterDoc() {
    Document doc;
    doc.SetObject(); // Make doc an object !
    doc.AddMember("text", generateInnerDoc(), jsonAlloc);
    return doc;
}
int main() {
    OStreamWrapper out(cout);
    Writer<OStreamWrapper> writer(out);
    generateOuterDoc().Accept(writer);
}
→ Ссылка