7

I'm making a class and I want to return my class inside a method. My class has a rapidjson::Document object.

You can see the previous problems here: LNK2019: "Unresolved external symbol" with rapidjson

As I discovered, rapidjson prevent you to perform any kind of copy of the Document object, and then the default copy of the class containing a Document object failed. I'm trying to define my own Copy Constructor but I need to perform a copy of the object. I saw a way to hypothetically copy the object with .Accept() method, but is returning me a lot of errors inside the rapidjson::Document class:

error C2248: 'cannot access private member declared in class `rapidjson::GenericDocument'

This is my Copy Constructor:

jsonObj::jsonObj(jsonObj& other)
{
    jsonStr = other.jsonStr;
    message = other.message;

    //doc = other.doc;
    doc.Accept(other.doc);

    validMsg = other.validMsg;
}

I found in the code of the library (line 52-54) that "Copy constructor is not permitted".

This is my class:

class jsonObj {
    string jsonStr;
    Document doc; 

public:
    jsonObj(string json);
    jsonObj(jsonObj& other);

    string getJsonStr();
};

The method:

jsonObj testOBJ()
{
    string json = "{error:null, message:None, errorMessage:MoreNone}";
    jsonObj b(json);
    return b; //It fails here if I return a nested class with a rapidjson::Document in it. Returning NULL works
}

So how to perform a copy of the Document element?

Community
  • 1
  • 1
SysDragon
  • 9,692
  • 15
  • 60
  • 89
  • Reading over the documentation at this page of the [wiki user guide for rapidjson](https://code.google.com/p/rapidjson/wiki/UserGuide), it looks to me like you will need to rethink how you are composing the `jsonObj` class. If you want to actually make a copy of the rapidJson document then you will need to allocate a new document, and then explicitly copy the old document to the new document resulting in two different documents with the same data. So you will need to have a copy constructor, assignment, etc. for `jsonObj`. You may need to rethink your architecture and use of rapidJson. – Richard Chambers Mar 28 '14 at 12:43
  • @RichardChambers I already have a Copy and Assign Constructors, but idk how to copy the `Document` object without parse the json string every time. I need a class that contains the rapidjson library because I'm making a C++ library and I need to expose the json parser outside with the wrapper, so I need to return my class across a method with the `Document` in it. =/ – SysDragon Mar 28 '14 at 12:46
  • 2
    I think the only way to copy the document object is to do the parsing otherwise you run into the deep copy versus shallow copy with duplicated pointers and who owns what memory allocation issue. rapidJson seems to be designed for a single instance of any particular document so your wrapper will need to use move semantics and not copy semantics. It looks to me like you are trying to go against the architecture and design of rapidJson which is why I suggest you rethink your architecture or look at alternatives to rapidJson. – Richard Chambers Mar 28 '14 at 13:25
  • After reading previous question and this one I'm starting to think that @RichardChambers is right with his comment on the other hand one more thing I was thinking about rather than using document in a nested `class` create it without `Document` member and create it when scoping maybe that will allow another `Document instance`? – XAMlMAX Mar 31 '14 at 07:12
  • One option to investigate is using a `Document` pointer with `shared_ptr` or some similar reference counting mechanism. I am not familiar with rapidJson however my impression from what I have read is that a `Document` is a container that is analogous to a JavaScript variable so using `shared_ptr` as a way of providing a handle to an object in a garbage collected memory pool seems reasonable. – Richard Chambers Mar 31 '14 at 13:38
  • 1
    For those interested, `Document` now supports C++11 move semantics (as of commit `1950efd6760fc89a074ae5b989e560edded92578`), courtesy of yours truly. However it will not help the OP in implementing a copy constructor for objects containing a Document by value. – Emile Cormier Nov 08 '14 at 23:38
  • Is returning `jsonObj` from functions the only situation where you need `jsonObj` to be copyable? – Emile Cormier Nov 08 '14 at 23:44
  • @EmileCormier Yes, because the class is the only place that uses the Document element. Thank for your info, by the way. – SysDragon Nov 10 '14 at 09:28

4 Answers4

16

Use the CopyFrom method on a new Document:

rapidjson::Document inDoc;    // source document
rapidjson::Document outDoc;   // destination document
outDoc.CopyFrom(inDoc, outDoc.GetAllocator());

I tested this approach and changes made to the output document had no effect on the input document. Make sure the CopyFrom method is given the output document's allocator.

Ethan T
  • 1,390
  • 12
  • 28
  • It also works with non-Document types as long as the Object can be converted to a Value. `Value v = ...; outDoc.CopyFrom(v, outDoc.GetAllocator());` – Laposhasú Acsa Oct 15 '18 at 12:52
1

Repository https://github.com/rjeczalik/rapidjson have the DeepCopy patch which might help you copy one document into another.

ArtemGr
  • 11,684
  • 3
  • 52
  • 85
0

must use (const) reference as return type(try to store new documents in creator class), you can't copy documents, i.e. can't return by value, since implicitly you try to use disabled copy constructor

Roman
  • 21
  • 5
-1

I created this method to copy document object and it works fine for me:

static void copyDocument(rapidjson::Document & newDocument, rapidjson::Document & copiedDocument) {
    rapidjson::StringBuffer strbuf;
    rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
    newDocument.Accept(writer);
    std::string str = strbuf.GetString();
    copiedDocument.Parse<0>(str.c_str());
}
SysDragon
  • 9,692
  • 15
  • 60
  • 89
Arvind Kanjariya
  • 2,089
  • 1
  • 18
  • 23