Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QJsonObject: Modify field value



  • I have a QJsonObject like this:

    QJsonObject* json = new QJsonObject();
    _input_data->insert("Name", QJsonValue::fromVariant("Paul"));
    

    Now I would like to change the value, using:

    _input_data["Name"] = "Nyck";
    

    But I got a compilation error:

    error: array subscript is not an integer
    

    How can I change the value?


  • Qt Champions 2019

    First - why do you create the object on the heap instead simply on the stack?
    And then - since _input_data is a pointer, _input_data["Name"] will not do what you expect, you're looking for (*_input_data)["Name"]



  • @christian-ehrlicher thanks!

    I'm creating the object on the heap because this QJsonObject could be bigger then a stack size (1MB).


  • Qt Champions 2019

    @fem_dev said in QJsonObject: Modify field value:

    I'm creating the object on the heap because this QJsonObject could be bigger then a stack size (1MB).

    Although the object is created on the stack, the internal data of it won't be on the stack so it's not needed to create the object on the heap (and get all the drawbacks you're seeing).



  • @christian-ehrlicher thank you so much for this great information! I didn't know that!


  • Moderators

    @christian-ehrlicher said in QJsonObject: Modify field value:

    Although the object is created on the stack, the internal data of it won't be on the stack so it's not needed to create the object on the heap (and get all the drawbacks you're seeing).

    To add to @Christian-Ehrlicher, most of Qt's "data" objects should not be created on the heap, for example:

    • QJsonObject
    • QVector
    • QString
    • QImage
    • QIcon

    They are also very cheap to copy, so functions should return them by-value (not by-pointer or by-reference). Read https://doc.qt.io/qt-5/implicit-sharing.html



  • @JKSH woww...this is new for me: "Implicity sharing"...

    I read this Qt article, but I would like to confirm if I understant it in the right way.

    So, using Qt 5 framework, if I have some code like:

    void main()
    {
        QJsonObject json;
    
        // Fill this JSON object with some data...
    
        // Send data to a function:
        my_func(json)
    }
    

    This my_func() should be ALWAYS like

    void my_func(QJsonObject x)
    

    and NO in this tradicional way like:

    void my_func(QJsonObject &x)
    

    I said ALWAYS because if my_func() do not modify the json input argument, it will be passed by reference, like QJsonObject &x.
    But if the my_func() modify the json input argument, it will be passed by value, like QJsonObject x.

    Is this afirmation correct?


  • Lifetime Qt Champion

    Hi @fem_dev,

    The general rule of thumb is: if the size of your object is <= 16 bytes, then pass by value: void my_func(Object x), otherwise pass by const reference: void my_func(const Object &x). Just to be clear: that's the object's size, not the data's size! Most Qt objects are not much more than a pointer to private data + a few bytes for organisation. That's why it's cheap to pass them by value.

    If you need to modify the object within the function, you have to pass the object as pointer or reference: void my_func(Object &x) or void my_func(Object *x).

    Note that Qt (and personally me) prefer the pointer syntax, as this makes it more obvious the object is modified in the function:

    void my_func(Object *o);
    
    void test()
    {
      Object x;
      my_func(&x);
    }
    

    I said ALWAYS because if my_func() do not modify the json input argument, it will be passed by reference, like QJsonObject &x.

    No, you pass by const-ref or by value here.

    But if the my_func() modify the json input argument, it will be passed by value, like QJsonObject x.

    If you pass by value, you can modify the object within my_func, but that will not change it outside my_func(). Not sure if I understand what you mean here.

    Regards



  • @aha_1980 said in QJsonObject: Modify field value:

    Not sure if I understand what you mean here.

    Yes @aha_1980, I undertood you and I agree with it!

    My confusion is about the @Christian-Ehrlicher explanation here:

    @JKSH said in QJsonObject: Modify field value:

    so functions should return them by-value (not by-pointer or by-reference).

    So, in this example below, I want to return a BIG QJsonObject. What should I do?

    Example 1:

    void my_func(const QJsonObject &json);
    
    void main() 
    {
        // Create a QJsonObject outside the function:
        QJsonObject big_json;
    
        // Fill this object with data...
    
        // Send data to the function:
        my_func(big_json)
    
        // Use the modified QJsonObject...
    }
    

    Example 2:

    QJsonObject my_func(void);
    
    void main() 
    {
        // The QJsonObject will be created inside of 'my_func' and will be returned by value:
        QJsonObject big_json = my_func();
    
        // Use the QJsonObject...
    }
    

    My first idea is use the "Example 1" to avoid copying data, but when I read the @Christian-Ehrlicher response, I don't know which case I should use.

    Could you help me to understant the @Christian-Ehrlicher afirmation?



  • @fem_dev
    It would not matter which of these two you use.

    This is because there never is a "big" JSON object. QJsonObject is always small, because the JSON data is not stored actually in QJsonObject, instead that just holds a pointer to the data elsewhere. This is why @JKSH is saying QJsonObject is "cheap to copy" and that you can create it on the stack instead of the heap, since it's small.

    EDIT
    P.S.
    For you or anyone else reading this. Do read @JKSH's link to https://doc.qt.io/qt-5/implicit-sharing.html. You find QJsonObject listed among the Qt classes which utilise it.

    In summary this means that that your actual "big data" of the JSON content is stored internally by Qt elsewhere in some "shared object data table" instead of in your QJsonObject, and that just has a "conceptual pointer" to the data.

    The data is reference counted, which means that (a) Qt looks after disposing it once the final reference to it in code goes out of scope, so you don't have to worry about that, and (b) if code "copies" it (e.g. a QJsonObject) all Qt does internally is increment the reference count to that data blob, so it's very fast and does not cost extra memory. If you only access the data in the copy for read it stays "cheap" like that; if you write to the data then only at that instant does Qt make a copy of the data to a fresh area in the "shared table". So it's pretty efficient!



  • @JonB thank you! Now I got it!


Log in to reply