37

I am doing something like this:

#include <signal.h>

class myClass {
public: 
    void myFunction () 
    {
        signal(SIGIO,myHandler);
    }

    void myHandler (int signum)
    {
        /**
        * Handling code
        */
    }

}

I am working on Ubuntu, using gcc.

But it won't compile. It is complaining with:

error: the argument with type void (MyClass::)(int) doesn't agree with void (*) (int)

Any clues? Or maybe it is just that I cannot use a signal inside classes? Are signals only allowed in C?

The error message is an approximate translation because my compiler is not in English.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
Pablo Herrero
  • 1,724
  • 5
  • 18
  • 23
  • Beware that Signals are not threadsafe, so you might not want to reconsider this if necesarry – Robert Gould Dec 05 '08 at 08:55
  • 1
    The reason you need to use a static method (as described below), is that to call a method you need an instance of the class (an object). There is no way to pass an object to signal so it must be a normal function pointer (not a method pointer). – Martin York Dec 05 '08 at 17:27
  • @Robert Gould: True; but not really relevant to the subject. – Martin York Dec 05 '08 at 17:28

6 Answers6

46

The second parameter of signal should be a pointer to a function accepting an int and returning void. What you're passing to signal is a pointer to a member function accepting an int and returning void (its type being void (myClass::*)(int)). I can see three possibilities to overcome this issue:

1 - Your method myHandler can be static: this is great, make it static

class myClass 
{
  public:
    void myFunction () 
    {
        signal(SIGIO, myClass::myHandler);
    }

    static void myHandler (int signum)
    {
        // handling code
    }
};

2 - Your method shouldn't be static: if you're planning to use signal with only one instance, you can create a private static object, and write a static method that simply call the method on this object. Something along the lines of

class myClass 
{
  public:
    void myFunction () 
    {
        signal(SIGIO, myClass::static_myHandler);
    }

    void myHandler (int signum)
    {
        // handling code
    }

    static void static_myHandler(int signum)
    {
        instance.myHandler(signum);
    }

  private:
    static myClass instance;
};

3 - However, if you're planning on using the signal with multiple instances, things will get more complicated. Perhaps a solution would be to store each instance you want to manipulate in a static vector, and invoking the method on each of these :

class myClass
{
  public:
    void myFunction () // registers a handler
    {
        instances.push_back(this);
    }

    void myHandler (int signum)
    {
        // handling code
    }

    static void callHandlers (int signum) // calls the handlers
    {
        std::for_each(instances.begin(), 
                      instances.end(), 
                      std::bind2nd(std::mem_fun(&myClass::myHandler), signum));
    }
  private:
    static std::vector<myClass *> instances;
};

and somewhere, do a single call to

signal(SIGIO, myClass::callHandlers);

But I think that if you end up using the last solution, you should probably think about changing your handling design :-)!

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
  • 1
    Your second example isn't standard C++. – dalle Dec 05 '08 at 17:24
  • 1
    Is that because I forgot the static keyword? If so, it's corrected! – Luc Touraille Dec 06 '08 at 21:23
  • 1
    this is the error that I am getting when I followed your second method `error: 'instance' was not declared in this scope` – molecule Aug 24 '16 at 06:24
  • 1
    @molecule: `instance` is declared at the end of the class, in the private section. – Luc Touraille Aug 24 '16 at 09:06
  • 2
    I tried #2 as well as a solution and getting the same issue with the undefined reference to `myClass::instance'. And I did change the myClass to the class I was using. I know c++ but this issue is throwing me for a loop. – Tim Herbert Mar 17 '20 at 16:25
12

To pass a pointer to a method, it must be a static method and you must specify the class name.

Try this:

class myClass {
  void myFunction () 
  {
    signal(SIGIO, myClass::myHandler);
  }

  static void myHandler (int signum)
  {
     // blabla
  }
};

And you should also read the link supplied by Baget, the paragraph 33.2 in the C++ FAQ.

Jørn Jensen
  • 998
  • 1
  • 10
  • 17
3
#include <signal.h>

class myClass {

 private:
  static myClass* me;

 public:
  myClass(){ me=this; }

  void myFunction (){
    signal(SIGIO,myClass::myHandler);
  }

  void my_method(){ }

  static void myHandler (int signum){
    me->my_method();
 }
}
gekomad
  • 525
  • 9
  • 17
  • 1
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – NathanOliver Sep 24 '15 at 15:21
3

Actually, C++ signal handlers are not permitted to use any facilities not present in both C and C++ (except that in C++11 they may use atomics), and are required to use C linkage. Quoting C++11 draft n3242 section 18.10 "Other runtime support" [support.runtime] (paragraph 8),

The common subset of the C and C++ languages consists of all declarations, definitions, and expressions that may appear in a well formed C++ program and also in a conforming C program. A POF (“plain old function”) is a function that uses only features from this common subset, and that does not directly or indirectly use any function that is not a POF, except that it may use functions defined in Clause 29 that are not member functions. All signal handlers shall have C linkage. A POF that could be used as a signal handler in a conforming C program does not produce undefined behavior when used as a signal handler in a C++ program. The behavior of any other function used as a signal handler in a C++ program is implementation-defined.

(Clause 29 being the one on atomics.)

SamB
  • 9,039
  • 5
  • 49
  • 56
1

It does seem crazy that you can post new answers with less reputation than it takes to comment on existing ones, but there we go.

gekomad's answer from Sept 24 2015 was the one that I used to solve my problem. It is worth pointing out that this will only work completely obviously when there is only ever one instance of myClass created. otherwise, the static object pointer will point to one of the instances (the most recently created) which may not be the desired one.

And, in case it is useful to someone else, a valid 2018 URL for the FAQ question linked in a couple of the answers is:

http://www.cs.technion.ac.il/users/yechiel/c++-faq/memfnptr-vs-fnptr.html

Michael Firth
  • 482
  • 5
  • 11
0

You can use singleton pattern

    static MyClass &getInstance() {
    static MyClass instance;
    return instance;
Abolfazl Abbasi
  • 309
  • 2
  • 12