Callback's flaws

2019-02-25 19:43发布

From: http://doc.qt.nokia.com/4.7/signalsandslots.html

Callbacks have two fundamental flaws: Firstly, they are not type-safe. We can never be certain that the processing function will call the callback with the correct arguments.

Can someone explain me, in what kind of situations it is not certain that the arguments won't be correct? What is the technical gist of that statement?

EDIT 1 As pointed out by Gui13 in the below post, the QString does give an error, when a char* is passed instead. But I tested the following program:

#include <iostream>
#include <QString>
#include <stdio.h>
typedef int (*callback_function)( QString *string);

int MyCallback( std::string string )
{
    if (string.empty() == false)
        std :: cout << string.length();
    return 0;
}

int main ()
{
    /* in another function */
    char *badQstring = (char*)"Booohhh";
    MyCallback( (std::string )badQstring ); 
}

It works properly. Does this mean that Qt's has some problems w.r.t callbacks and this does not imply that the flaw mentioned above is in plain C++ too or I am barking at the wrong tree?

标签: c++ qt callback
3条回答
SAY GOODBYE
2楼-- · 2019-02-25 20:19

Well, say Qt wants you to give him a callback that takes a pointer to a QString as its argument: your C++ typedef for the call back will look like:

typedef int (*callback_function)( QString *string);

Now, when this callback is called, you can never be sure that the argument passed is really a QString: in C++, this statement is valid and will very likely crash your callback:

int MyCallback( QString *string )
{
   if(string)
       printf("QString value: %s\n", string->toAscii());
}

/* in another function */
char *badQstring = "Booohhh";
MyCallback( (QString *)badQstring ); // crash, badQstring is not a QString!

Since C++ allows casting, you can never be sure of what type is actually passed to your callback. But, well, this statement is valid to whatever function, even if not a callback.

查看更多
The star\"
3楼-- · 2019-02-25 20:25

Please look at sqlite3_exec() as a good example. It's void* parameter is a pointer to a "context object" that is passed into the callback function when the latter is called. It's totally up to the user to be sure that this void* points to a type he expects.

For example, you need some complex class as a "context object". You pass an address of an object of that class into sqlite3_exec() and it's implicitly converted into void*, then when your callback is called you have to cast it back from void* and noone catches you if you cast it to the wrong type.

查看更多
闹够了就滚
4楼-- · 2019-02-25 20:32

It's a pointer to a function, and some compilers don't check that in run time there won't be a case where that pointer leads to a function with different parameters than expected.

查看更多
登录 后发表回答