Trouble referencing class in structure using this

2019-08-08 20:07发布

问题:

Header file:

// Free function to use in thread
unsigned int __stdcall WorkerFunction(void *);

class MyClass {
    public:
        int temp;
        void StartThread();
}

typedef struct {
    MyClass * cls;
} DATA;

CPP class:

void MyClass::StartThread() {
    temp = 1234;
    DATA data = {this};

    HANDLE hThread = (HANDLE) _beginthreadex(0, 0, &WorkerFunction, &data, 0, 0);

    // Commented out for now while I address the current problem
    //CloseHandle(hThread);
}

unsigned int __stdcall WorkerFunction(void * param0) {
    MessageBox(NULL, "WorkerFunction()", "Alert", MB_OK);
    DATA * data = (DATA *) param0;
    MyClass* cls0 = data->cls;

    // Crashes when reference to cls0 is attempted.
    char buf[5];
    snprintf(buf, 5, "%i", cls0 ->temp);
    MessageBox(NULL, buf, "Alert", MB_OK);
}

I've got an easy problem here that I can't put my finger on.

  • I have params for a thread, which pass a struct which contains a class.
  • I instantiate the struct with this and then pass it when the thread starts
  • I try to dereference (?) it in the worker function.
  • At this point, everything compiles OK.
  • When I add lines to access something in the class, the app crashes.

Where is my mistake?

回答1:

You're passing a local stack variable that is out-of-scope the moment StartThread() returns. You are therefore referencing stack-space that no longer belongs to you.

void MyClass::StartThread() {
    temp = 1234;
    DATA data = {this}; // << LOCAL VARIABLE OUT OF SCOPE ON FUNCTION EXIT

    HANDLE hThread = (HANDLE) _beginthreadex(0, 0, &WorkerFunction, &data, 0, 0);

    // Commented out for now while I address the current problem
    //CloseHandle(hThread);
}

Either dynamically allocate the data, or better still, make the data a member of MyClass and pass this as the thread data. In your case you're only passing *this anyway through a struct, so just pass it as the param

void MyClass::StartThread() {
    temp = 1234;

    HANDLE hThread = (HANDLE) _beginthreadex(0, 0, &WorkerFunction, this, 0, 0);

    // Commented out for now while I address the current problem
    //CloseHandle(hThread);
}

And in your thread proc:

unsigned int __stdcall WorkerFunction(void * param0) {
    MessageBox(NULL, "WorkerFunction()", "Alert", MB_OK);
    MyClass* cls0 = static_cast<MyClass*>(param0);

   etc...
}

Whatever you pass to your thread procedure, it must have valid lifetime for the duration required. by the thread. Either ensure that by passing ownership of a dynamic allocation to the thread at let it do the delete, or pass a pointer known hold determinate state for the lifetime of its usage in the thread-proc. It appears this fulfills the latter, so you should likely be good to go.