Address of a class member function - c++

I have a class called CSum which contains a static method who's identifier is:
static double fileProc(string myFile);
In my main function I would simply call it by
CSum::fileproc("foo.txt")
However, I will like to invoke pthreads on two separate files. Therefore I need to obtain the address of this method. I do so by
return1 = pthread_create(&t1, NULL, &CSum::fileProc(file1), NULL);
return2 = pthread_create(&t2, NULL, &CSum::fileProc(file2), NULL);
But I get an error
lvalue required as a unary '&' operand.
Any suggestions?

You don't pass parameters, you just give the name of the function. The parameter you want it to get is the next parameter of the pthread_create.
Instead of
pthread_create(&t2, NULL, &CSum::fileProc(file2), NULL);
do
pthread_create(&t2, NULL, &CSum::fileProc, file2);
Cast types as appropriate. Note that the thread function is supposed to accept a pointer as a parameter, make sure you define it appropriately.

CSum::fileProc(file1) is an expression that calls the function and gives you the value the function returns as the value of the expression. You are trying to take the address of that value, which you can't, and this won't do what you want.
&CSum::fileProc will give you the function pointer, but it does not have the correct signature for use with pthreads. Since pthreads is a C library, it has a very simplistic interface. Your best bet for C++ is to use a higher-level C++ library that uses pthreads underneath (at least on unixes), like boost threads.
If for some reason yoou can't do that, you need to write your own wrappers. To call your function in a separate thread, you would need to write something like:
class CSum {
...
static void fileProcWrapper(void* param) {
const char* fileName = (const char*) param;
fileProc(fileName);
}
...
and call it with
pthread_create((&t2, NULL, &CSum::fileProc, (void*) file1.c_str());
That just gives you the call, mind, the result is thrown away with this code. If you want to collect the result with pthread_join, you have to do a bit more work.

Related

Using callbacks in C++

I'm working on a project in C++, but at some point in the application it fails and generates a core dump. The application uses a couple of classes, which for the purposes here I'm concentrating on one of the classes, which I'm calling A, and is instantiated as object a. This has a large number of member functions, of which at the moment only a few are being used, but one of these generates a log to produce diagnostics to be used for debugging. I want to use this to find out why the application is failing.
The project is to put together code that invokes the various member functions, and although I have access to the source code and some limited documentation, none of the code can be changed, with all changes being in the code that makes use of the classes and invokes the member functions. The member function in question is:
void enable_log (log_callback callback, void * user_data = nullptr)
where the 1st argument callback contains the message and 2nd argument is optional. For now it can be set to nullptr, so would be invoked as:
a.enable_log(callback, nullptr);
From this documentation it's not at all clear what exactly callback is. However, in looking at the source code this is:
using log_callback = void (*)(const std::string& message, void* user_data);
in a header file, where log_callback is an alias for const std::string& if I understand this correctly.
I already have dummy classes on a platform using Visual Studio 2019 with some test member functions to simulate invoking the member functions on a remote Linux server, but I'm unable to find a way of making use of the member function above. I added the test member function to the dummy class as follows:
void enable_log(const std::string& callback, void* user_data = nullptr) {
callback = "ABCD";
}
which is supposed to generate a test string which is returned, such that in the real application this string will have diagnostic information that will be written to a file. However, the "=" is an error.
The idea is that in the main function an empty string will be declared, then enable_log() should populate this string, which can be printed out.
I've spent some time looking at various resources, including Stackoverflow, but I cannot find a way of returning a string with the information that can be printed out. I need a simple way to simulate this, and as I said above, I must not change the source code of the real member function, so the simulated member function has to produce a string in the same way. How is this done? Some advice would be appreciated.
Callback, in simple words, is some function that will be called later at some point. Example:
void callback_fn(int a);
using callback_t = (void)(*)(int a);
void some_func(callback_t);
You can use some_func() like so:
some_func(callback_fn);
Full example here: https://godbolt.org/z/ET3GhfYrv
For your usecase the parameters of the callback are slightly different. Here's how to read the syntax:
using log_callback = // this just creates an alias for whatever is on the right handside
void // the return type of the "callable" should be void
(*) // this tells us that it is a function pointer
(const std::string& message, void* user_data) // These are the arguments the callable takes. It is a "std::string" and a "void *"
To use this, just create a free function with the same signature:
void callable(const std::string &msg, void *userData = nullptr)
{
// msg is the data sent by the function. use it in whatever way
// you want.
std::cout << msg << '\n';
}
// Pass it to the enable_log
enable_log(callable);

Was it possible to get a pointer to member from an instance of an object?

I was porting some legacy code to VS 2015 when this compiler error halted the build:
error C3867: 'OptDlg::GetFullModel': non-standard syntax; use '&' to create a pointer to member
Going to the corresponding file and line, I saw this:
Manager mgr = GetDocument()->GetManager();
OptDlg dlg;
...
mgr->SetFullModel(dlg.GetFullModel);
if ( dlg.GetFullModel )
mgr->SetSymm(...
GetFullModeland SetFullModel are the getter/setter pair for a member variable in two different classes:
class Manager {
...
bool GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bFlag) { m_bFullModel = bFlag; }
....
};
class OptDlg {
...
void GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bValue) { m_bFullModel = bValue; if ( bValue ) m_bInside = 0;}
Yep, something's wrong. Was dlg.GetFullModel supposed to be a pointer to a member function? I thought those use the class name, not an instance. Not to mention what that would mean for execution semantics...
C++ is still relatively new to me, so I tried Google. It had a lot on function pointers, but they all looked different from what I had:
&OptDlg::GetFullModel // Standard-compliant
vs
OptDlg::GetFullModel // The "normal" way to mess up getting a pointer to member, it seems
vs
dlg.GetFullModel // ?
Is dlg.GetFullModel just another way of getting a pointer to member function? If not, what is the "standard C++ version", if there is one? Is this just another one of those VS 6 "extensions"?
&OptDlg::GetFullModel // Standard-compliant
If your parameter types were supposed to be taking member functions, that's what you'd use. But they take booleans. It looks like you're just missing parentheses on your function calls, and it should be:
mgr->SetFullModel(dlg.GetFullModel());
if (dlg.GetFullModel())
mgr->SetSymm(...
Probably someone was ignoring warnings (or didn't have them on) and hence a pointer value (being produced through whatever shady means) was always being interpreted as non-NULL, hence boolean true.
Is this just another one of those VS 6 "extensions"?
It would appear to be the case, although this comment is the only documented evidence I can find it was an intentional/advertised "feature". Don't see any formal announcement of it being added or taken out.
It strongly looks to me like someone mis-typed dlg.GetFullModel() (which would call the function), not that they were trying to get a member function pointer.
Presumably the legacy compiler let it slide, taking the address of the function without using & and converting the non-null function pointer to bool (with value true) to pass into the set function.

Pointer passing to function header

I have another problem regarding pointers.
I have a function with the following header:
addActor (NxuPhysicsCollection &c, NxActor &a, const char *userProperties=0, const char *actorId=0)
And I am trying to use it like this:
NXU::NxuPhysicsCollection* collection = new NXU::NxuPhysicsCollection();
NxActor* actor = *actors++;
NXU::addActor(collection, actor, NULL, NULL);
But I get the following error:
A reference of type "NXU::NxuPhysicsCollection&" (not const-qualified) cannot be initialised with a value of type "NXU::NxuPhysicsCollection*" (this is for the collection parameter, same error appears for actor as well)
How am I supposed to pass the collection and actor parameters to the function in order to work properly?
I tried this:
NXU::addActor(&collection, &actor, NULL, NULL);
But that doesn''t work either, it gives me the error:
"Initial value of reference to non-const must be a lvalue."
Any help is greatly appreciated.
Edit: If I use it like this:
NXU::addActor((NXU::NxuPhysicsCollection&)collection, (NxActor&)actor, NULL, NULL);
It does not give me errors anymore. Is this correct?
I must mention that NXU and NX namespaces are closed source and I cannot modify the way they are implemented
Since the formal arguments of your member function for c and a are references, while collection and actor are pointers, you need to dereference pointers to make them compatible with references:
// No need to pass NULLs for the defaulted parameters, so
// the trailing NULL, NULL are removed.
NXU::addActor(*collection, *actor);
Alternatively, you can change the signature of the constructor to accept pointers instead of references:
addActor (NxuPhysicsCollection *c, NxActor *a, const char *userProperties=0, const char *actorId=0)
// ^ ^
// | |
// Here and Here
Both the c and a parameters are references.
Pass them as:
NXU::addActor(*collection, *actor, NULL, NULL);
This act is called pointer-dereference.
NXU::addActor(*collection, *actor, NULL, NULL);
because
addActor (NxuPhysicsCollection &c, NxActor &a, const char *userProperties=0, const char *actorId=0)
receives collection and actor by reference, not by pointer

Error trying to make a basic ThreadManager in C++

I haven't coded much for probably a few years, and I wanted to make a really basic thread manager in C++ for an idea I had. I have ran into an issue where I get this error:
ThreadManager.cpp:49:37: error: cannot convert
'ThreadManager::updateLoop' from type 'DWORD (ThreadManager::)(LPVOID)
{aka long unsigned int (ThreadManager::)(void*)}' to type
'LPTHREAD_START_ROUTINE {aka long unsigned int
(attribute((stdcall)) )(void)}'
Yet, I don't know how to attempt to fix it. Here is my code, I couldn't figure out how to paste it in here with formatting. It said I needed 4 spaces on each line but that seemed like would take a while, so I put it on pastebin:
ThreadManager.cpp: http://pastebin.com/2bL3mTqv
ThreadManager.h: http://pastebin.com/7xETj5BK
Like I said, I haven't programmed much for a LONG time, and I am trying to get back into it with what I remember, so any help would be appreciated.
The comments have said the basics, but here's it spelled out: you can't pass in a method to a class when a call is expecting a normal function. To do what you want, I'd do the following:
// New Function
void threadMain(void* classPointer)
{
ThreadManager* realClass = (ThreadManager*)classPointer;
realClass->updateLoop();
}
ThreadManager::ThreadManager(int max)
{
// Assign maxThreads to max value
maxThreads = max;
// Start updateThread, and let it run updateLoop() until terminated
updateThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
threadMain, // thread function name
this, // argument to thread function
0, // use default creation flag
NULL); // ignore thread identifier
// Check the return value for success
// If failed, exit process.
if (updateThread == NULL) {
ExitProcess(3);
}
}
Now I know you want an extra argument, so probably use std::tuple to pass in the "this" pointer and any extra arguments you actually want.
Now having said all of that, take the advice of others and use std::thread and such, not the win32-specific calls unless you really need to.

I am new to threads, What does this compile error mean?

Using C++.
pthread_t threads[STORAGE]; // 0-99
...
void run()
Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL);
if (status != 0)
{
printf("pthread_create returned error code %d\n", status);
exit(-1);
}
...
void ClientHandler::updateMessages(void *)
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
...
Compile Error:
TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’
I can't figure out whats wrong.
Thanks in advance.
A pointer to a member function is different from a global function with the same signature since the member function needs an additional object on which it operates. Therefore pointers to these two types of functions are not compatible.
In this case this means that you cannot pass a member function pointer to pthread_create but only a pointer to a non-member (or static) function. A work around for this problem is to use the forth parameter of pthread_create to pass a pointer to a object to a global function which then calls the method of the passed object:
class ClientHandler {
public:
void updateMessages();
void run();
};
// Global function that will be the threads main function.
// It expects a pointer to a ClientHandler object.
extern "C"
void *CH_updateMessages(void *ch) {
// Call "real" main function
reinterpret_cast<ClientHandler*>(ch)->updateMessages();
return 0;
}
void ClientHandler::run() {
// Start thread and pass pointer to the current object
int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this);
...
}
It's nothing to do with threads, it's a normal C++ error, you're just passing an incompatible type of function pointer.
A function pointer is not the same as a member instance function pointer, even if their signature is the same; this is because there is an implicit reference to *this passed. You can't avoid this.
As pthread_create takes a free function, create a static function(is a free function) inside ClientHandler
static void Callback(void * this_pointer,int other_arg) {
ClientHandler* self = static_cast< ClientHandler*>(this_pointer);
self-> updateMessages(other_arg);
}
and call pthread_create as follows
pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg);
That works because Callback is free function
YoLinux has a nice pthread tutorial that my help you in learning about threads.
As others have already said, the problem is that the signatures between the functions are different. Class member functions always have a "secret" extra parameter, the this pointer. So you can never pass a member function where a global function is expected. You can hack around this either with libraries such as Boost.Bind, or by making the function a static member of the class.
But the simplest, and most elegant solution is to use a different threading API.
Boost.Thread is a very nice threading library for C++ (pthreads is designed for C, and that's why it doesnt play well with C++ features such as class methods).
I'd recommend using that.
Your code could be rewritten as something like this:
class ClientHandler {
public:
ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...}
void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
// whatever arguments you want to pass to the thread can be stored here as member variables
};
boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array
gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));
You're passing a member function instead of a global, normal, one.
Just define:
void updateMessages(void *) {
static ClientHandler c;
// use c..
}