Можно ли использовать сигнал внутри класса C++?

Я делаю что-то вроде этого:

#include <signal.h>

class myClass {

    public: 

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

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

    }

Я работаю над Ubuntu, используя gcc.

но он не будет компилироваться. Он жалуется:

ошибка: аргумент типа void (MyClass::)(int) не согласен с void (*) (int)

какие-то зацепки? Или, может быть, я просто не могу использовать сигнал внутри классов? Сигналы разрешены только в C?

сообщение об ошибке является приблизительным переводом, потому что мой компилятор не находится в Английский.

6 ответов


второй параметр сигнала должен быть указателем на функцию, принимающую int и возвращающую void. То, что вы передаете сигналу, является указателем на функция, принимающая int и возвращающая void (ее тип void (myClass::*)(int)). Я вижу три возможности для преодоления этой проблемы:

1 - метод myHandler может быть статическим: это здорово, сделайте его статическим

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

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

2 - Ваш метод не должен быть статическим: если вы планируете использовать сигнал с только один экземпляр можно создать частный статический объект и написать статический метод, который просто вызовет метод для этого объекта. Что-то вроде

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 - однако, если вы планируете использовать сигнал с нескольких экземпляров, все будет сложнее. Возможно, решением было бы сохранить каждый экземпляр, которым вы хотите манипулировать, в статическом векторе и вызвать метод на каждом из них:

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;
};

и где-то, сделать один звонок к

signal(SIGIO, myClass::callHandlers);

но я думаю, что если вы в конечном итоге используете последнее решение, вам, вероятно, следует подумать об изменении дизайна обработки :-)!


чтобы передать указатель на метод, он должен быть статическим методом, и вы должны указать имя класса.

попробуйте это:

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

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

и вы также должны прочитать ссылку на багет,пункт 33.2 в C++ FAQ.


на самом деле обработчикам сигналов c++ не разрешается использовать какие-либо средства, отсутствующие как в C, так и в C++ (за исключением того, что в C++11 они могут использовать atomics), и требуется использовать C-связь. Цитата C++11 проект n3242 раздел 18.10 "другая поддержка выполнения" [поддержка.runtime] (пункт 8),

общее подмножество языков C и C++ состоит из всех объявлений, определения и выражения, которые могут появиться в хорошо сформированной программе на C++ а также в программы соответствии с. POF ("простая старая функция") является функция, которая использует только объекты из этого общего подмножества, а не прямо или косвенно используйте любую функцию, которая не является POF, за исключением того, что она может использовать функции, определенные в пункте 29, которые не являются функциями-членами. Все обработчики сигналов должны иметь с рычага. POF, который можно использовать в качестве сигнала обработчик в соответствующей программе C не производит неопределенное поведение, когда используется в качестве обработчика сигналов в программе на C++. Поведение любой другой функции используется в качестве обработчика сигнала в C++ программе определяется реализацией.

(п. 29, будучи один на Атомикс.)


#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();
 }
}

прочитайте следующий раздел (33.2):

C++ FAQ-указатели на участников


кажется сумасшедшим, что вы можете публиковать новые ответы с меньшей репутацией, чем требуется, чтобы комментировать существующие, но мы идем.

ответ гекомада от 24 сентября 2015 года был тем, который я использовал для решения своей проблемы. Стоит отметить, что это будет работать только совершенно очевидно, когда есть только один экземпляр myClass создать. в противном случае указатель статического объекта будет указывать на один из экземпляров (самый последний созданный), который может быть нежелательным один.

и, в случае, если это полезно кому-то еще, действительный URL 2018 для вопроса FAQ, связанного в нескольких ответах:

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