0

When I use rapidjson document as member variable and do this:

class Test
{
     rapidjson::Document    m_jsonDocument;

public:
    void f()
    {
        // WORKS FINE
        rapidjson::Document document;
        if (document.Parse<0>("{ \"hello\" : \"world\" }").HasParseError())
            printf("ERROR PARSING JSON\n");
        else
            printf("%s\n", document["hello"].GetString());


         // BUT HERE THROWS, WHY?
         if (m_jsonDocument.Parse<0>("{ \"hello\" : \"world\" }").HasParseError())
             printf("ERROR PARSING JSON\n");
         else
            printf("%s\n", m_jsonDocument["hello"].GetString());
    }
};

When I call if (m_jsonDocument.Parse<0>("{ \"hello\" : \"world\" }").HasParseError()) app crashes on line flags_ = defaultFlags[type]; in document.h in CTOR GenericValue(Type type). Visual Studio debugger says "Unable to read memory." for _flags. What is the problem? What is the difference between member variable and local variable?


EDIT: I set f as a callback using setResponseCallback defined here and f is being called as a callback using dispatchResponseCallbacks defined here.

Narek
  • 38,779
  • 79
  • 233
  • 389
  • How do you call the function `f`? – Some programmer dude May 13 '14 at 12:58
  • @JoachimPileborg There is a call to server for JSON data, and there is a callback which is being called when response is arrived. `f` is the callback function. Does it matter? – Narek May 13 '14 at 13:00
  • @JoachimPileborg Oh this is really strange. I cannot understand. I have called `f` as follows: `Test t; t.f();` and it worked. What is the difference? How can I fix my issue? – Narek May 13 '14 at 13:08

2 Answers2

2

The problem is, most likely, that you when the member function pointer f is called it's called without an actual object, meaning that the this pointer in the member function is invalid. This leads to undefined behavior when you try to access member variables, as those accesses uses the (invalid) this pointer implicitly.

There are a couple of ways to solve this, the most straightforward is to use a static member function as callback, and pass an instance of the object as user-data (most callback systems allow this). Then the static member function can use the user-data object pointer to call the real function.

Something like

class Test
{
    ...

public:
    static void f_wrapper(Test* object)
    {
        object->f();
    }
};

Then do e.g.

Test object;
set_callback(&Test::f_wrapper, &object);

Take care that object doesn't go out of scope.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I use `coco2d::network::HttpRequest` in case if you are familiar with this. It has `setResponseCallback` which takes two arguments: `this` and a pointer to the method. (The class should inherit from Layer class.) And when the response is back the callback is being called like this: ` if (pTarget && pSelector) { (pTarget->*pSelector)(this, response); }` where `pTarget` is the passed `this`, and `pSelector` is passed method. As you see it calls with `this`. – Narek May 13 '14 at 13:21
  • Another thing I can't understand how you can call non-static method without `this`? – Narek May 13 '14 at 13:22
  • @Narek If you pass `&Test::f` as a callback function, the code calling your function will happily call `Test::f` but it doesn't know it's a non-static member function and so will call it as an ordinary function, leading to this problem. – Some programmer dude May 13 '14 at 13:24
  • @Narek I also think you need to edit your question and add more code to show what you're doing, if possible a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – Some programmer dude May 13 '14 at 13:26
  • But call is being done like this: `pTarget->*pSelector` which is equivalent to `this->*pointerToF`. Doesn't it mean that I call `f` with `this`? – Narek May 13 '14 at 13:27
  • @Narek If `pTarget` is a pointer to an `Test` instance, then yes it should work. Have you used a debugger and looked at the call-stack to see that `pTarget` is a valid `Test` instance pointer? – Some programmer dude May 13 '14 at 13:32
  • I have used debugger, but it is not valid I guess :(. I have added an `EDIT` part, to describe my problem better. Also I have tested to use pointer to `rapidjson::Document` as a member variable, and I do `m_jsonDocument = new rapidjson::Document();` right before parsing and it works. Therefore, I tend to think that the problem you described is not my case. What you think? – Narek May 13 '14 at 13:41
  • I have found the problem. This was so stupid. I have create `Test t;` in stack, and when response was back `t` was destroyed, and, hence, it was invalid. But you helped me to go to the right direction. Thank you! :) – Narek May 13 '14 at 14:03
0

As @JoachimPileborg noted it should be important how I call f(); One of the reasons he explained in details. Thanks to Joachim for directing to the right direction. Actually my problem was more stupid than Joachim could think :). The problem was that I was calling f when the response to my HTTP request is back (f was a callback function). But as far as I allocated Test t; in stack, therefore the memory was de-allocated and this was invalid in the point when the response was back. I know, that is really stupid :).

Narek
  • 38,779
  • 79
  • 233
  • 389