-1

I am passing a parameter to a function using a function pointer. For some reason when I pass it in (the output of ClassA::parseData) I get garbage data. I am allocating the int to hold it in the heap so that I make sure the problem is not that the stack gets wiped out and thats why the variable doesn't exist. However, this hasn't fixed the problem. I have tried passing the int by value, reference, and pointer but I always get garbage data. What am I doing wrong?

ClassA.h

class ClassA
{
public:
    ClassA();
    ~ClassA();
    void setFunctionPointers();
    void parseData(int* dataBuffer);
};

ClassA.cpp

ClassB aClassB;

ClassA::ClassA(){}

ClassA::~ClassA(){}

void ClassA::setFunctionPointers(){
    aClassB.startTheThread((void (*)(int*)) &ClassA::parseData);
}

void ClassA::parseData(int* data){
    printf ("data received: %d \n", *data);
}

ClassB.h

class ClassB
{
    public:
        ClassB();
        ~ClassB();
        void* dataReader(void*);
        void startTheThread(void (*parseFunction)(int*));
        void (*_theParseFunction)(int*);
        pthread_t _theDataReaderThread;
};

ClassB.cpp

int* intPointer;

ClassB::ClassB(){}

ClassB::~ClassB(){
    delete intPointer;
}

void* ClassB::dataReader(void*){
    intPointer = new int;
    *intPointer = 5;
    while (true){
        _theParseFunction(intPointer);
        sleep(2);
    }
}

void ClassB::startTheThread(void (*parseFunction)(int*)){
    _theParseFunction = parseFunction;

    int threadReturn = pthread_create(&_theDataReaderThread,
                                      NULL,
                                     (void* (*)(void*)) &ClassB::dataReader,
                                      this);
}

main method

int main()
{
    ClassA aClassA = ClassA();
    aClassA.setFunctionPointers();

    while(true)
    {

    }

    return 0;
}
  • 4
    `pthread_create(... (void* (*)(void*)) &ClassB::dataReader, this)` is straight up invalid. – KamilCuk Aug 27 '19 at 21:31
  • FWIW if you can use C++11 or better you can use `std::thread` and a lambda instead of `pthread` and `void *`'s. It makes life a lot easier. – NathanOliver Aug 27 '19 at 21:33
  • 1
    A pointer to a non-static member function **cannot** be cast to a pointer to a function. If you ever find yourself casting function pointers you're almost certainly doing something wrong (loading a function from a DLL being the somewhat common exception to that rule). – Miles Budnek Aug 27 '19 at 21:35
  • 1
    If you replace the c-style cast to the function pointer to a `static_cast`, you'll see that the compiler refuse to perform the cast. – Guillaume Racicot Aug 27 '19 at 21:35
  • Possible duplicate of [Function pointer to member function](https://stackoverflow.com/questions/2402579/function-pointer-to-member-function) – JaMiT Aug 27 '19 at 21:43
  • 1
    Members take an implicit "this" pointer, so it's not the same signature at all. That you couldn't get it to compile until you casted the member function should have been a good indicator that something was probably wrong there. – Chris Uzdavinis Aug 27 '19 at 22:00

1 Answers1

1

The problem is on these lines:

aClassB.startTheThread((void (*)(int*)) &ClassA::parseData);
...
pthread_create(&_theDataReaderThread,
                                      NULL,
                                     (void* (*)(void*)) &ClassB::dataReader,
                                      this);

Those are invalid type-casts. You cannot cast a non-static method pointer into a function pointer like this. pthread_create() requires a standalone function or class static method only.

If you are using C++11 or later, try this instead:

ClassA.h

class ClassA
{
public:
    ClassA();
    ~ClassA();
    void setFunctionPointers();
    void parseData(int* dataBuffer);
};

ClassA.cpp

#include "ClassB.h"

ClassB aClassB;

ClassA::ClassA(){}

ClassA::~ClassA(){}

void ClassA::setFunctionPointers(){
    aClassB.startTheThread( [this](int *dataBuffer){ this->parseData(dataBuffer); } );
}

void ClassA::parseData(int* data){
    std::cout << "data received: " << *data << "\n";
}

ClassB.h

#include <functional>
#include <pthread.h>

class ClassB
{
public:
    using ParseFunction = std::function<void(int*)>;
    ClassB();
    ~ClassB();
    static void* dataReader(void*);
    void startTheThread(ParseFunction parseFunction);
    ParseFunction _theParseFunction;
    pthread_t _theDataReaderThread;
};

ClassB.cpp

int* intPointer;

ClassB::ClassB(){}

ClassB::~ClassB(){
    delete intPointer;
}

void* ClassB::dataReader(void *arg){
    ClassB *pThis = static_cast<ClassB*>(arg);
    intPointer = new int(5);
    while (true){
        pThis->_theParseFunction(intPointer);
        sleep(2);
    }
}

void ClassB::startTheThread(ParseFunction parseFunction){
    _theParseFunction = std::move(parseFunction);

    int threadReturn = pthread_create(&_theDataReaderThread,
                                    NULL,
                                    &ClassB::dataReader,
                                    this);
}

main method

int main()
{
    ClassA aClassA = ClassA();
    aClassA.setFunctionPointers();

    while(true)
    {

    }

    return 0;
}

Though, you really should be using std::thread instead of pthread_create():

ClassA.h

class ClassA
{
public:
    ClassA();
    ~ClassA();
    void setFunctionPointers();
    void parseData(int* dataBuffer);
};

ClassA.cpp

#include "ClassB.h"

ClassB aClassB;

ClassA::ClassA(){}

ClassA::~ClassA(){}

void ClassA::setFunctionPointers(){
    aClassB.startTheThread( [this](int *dataBuffer){ this->parseData(dataBuffer); } );
}

void ClassA::parseData(int* data){
    std::cout << "data received: " << *data << "\n";
}

ClassB.h

#include <functional>
#include <thread>

class ClassB
{
public:
    using ParseFunction = std::function<void(int*)>;
    ClassB();
    ~ClassB();
    void dataReader();
    void startTheThread(ParseFunction parseFunction);
    ParseFunction _theParseFunction;
    std::thread _theDataReaderThread;
};

ClassB.cpp

int* intPointer;

ClassB::ClassB(){}

ClassB::~ClassB(){
    delete intPointer;
}

void ClassB::dataReader(){
    intPointer = new int(5);
    while (true){
        _theParseFunction(intPointer);
        sleep(2);
    }
}

void ClassB::startTheThread(ParseFunction parseFunction){
    _theParseFunction = std::move(parseFunction);
    _theDataReaderThread = std::thread([this](){ this->dataReader(); });
}

main method

int main()
{
    ClassA aClassA = ClassA();
    aClassA.setFunctionPointers();

    while(true)
    {

    }

    return 0;
}

However, if you are using a pre-C++11 compiler, then you have to use a plain pointer-to-member-function instead:

ClassA.h

class ClassA
{
public:
    ClassA();
    ~ClassA();
    void setFunctionPointers();
    void parseData(int* dataBuffer);
};

ClassA.cpp

#include "ClassB.h"

ClassB aClassB;

ClassA::ClassA(){}

ClassA::~ClassA(){}

void ClassA::setFunctionPointers(){
    aClassB.startTheThread(&ClassA::parseData, this);
}

void ClassA::parseData(int* data){
    std::cout << "data received: " << *data << "\n";
}

ClassB.h

#include <pthread.h>

class ClassA;

class ClassB
{
public:
    typedef void (ClassA::*ParseFunction)(int*);
    ClassB();
    ~ClassB();
    static void* dataReader(void*);
    void startTheThread(ParseFunction parseFunction, ClassA*);
    ParseFunction _theParseFunction;
    ClassA *_theParseObj;
    pthread_t _theDataReaderThread;
};

ClassB.cpp

int* intPointer;

ClassB::ClassB(){}

ClassB::~ClassB(){
    delete intPointer;
}

void* ClassB::dataReader(void *arg){
    ClassB *pThis = static_cast<ClassB*>(arg);
    intPointer = new int(5);
    while (true){
        pThis->_theParseObj->*(pThis->_theParseFunction)(intPointer);
        sleep(2);
    }
}

void ClassB::startTheThread(ParseFunction parseFunction, ClassA *parseObj){
    _theParseFunction = parseFunction;
    _theParseObj = parseObj;

    int threadReturn = pthread_create(&_theDataReaderThread,
                                    NULL,
                                    &ClassB::dataReader,
                                    this);
}

main method

int main()
{
    ClassA aClassA = ClassA();
    aClassA.setFunctionPointers();

    while(true)
    {

    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770