【问题标题】:Is it possible to use signal inside a C++ class?是否可以在 C++ 类中使用信号?
【发布时间】:2010-09-25 11:40:25
【问题描述】:

我正在做这样的事情:

#include <signal.h>

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

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

}

我正在使用 gcc 在 Ubuntu 上工作。

但它不会编译。它抱怨:

错误:void (MyClass::)(int) 类型的参数与 void (*) (int) 不一致

有什么线索吗?或者也许只是我不能在类中使用信号?信号只允许在 C 中使用吗?

错误信息是近似翻译,因为我的编译器不是英文的。

【问题讨论】:

  • 请注意信号不是线程安全的,因此如果需要,您可能不想重新考虑这一点
  • 之所以需要使用静态方法(如下所述),是因为调用方法需要类的实例(对象)。无法将对象传递给信号,因此它必须是普通函数指针(而不是方法指针)。
  • @罗伯特古尔德:是的;但与主题无关。

标签: c++ signal-handling


【解决方案1】:

signal 的第二个参数应该是一个指向接受 int 并返回 void 的函数的指针。您传递给信号的是一个指针,指向一个接受 int 并返回 void 的 member 函数(其类型为 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);

但我认为,如果您最终使用最后一种解决方案,您可能应该考虑更改您的处理设计:-)!

【讨论】:

  • 您的第二个示例不是标准 C++。
  • 是因为我忘记了静态关键字吗?如果是,那就更正了!
  • 这是我按照你的第二种方法时遇到的错误error: 'instance' was not declared in this scope
  • @molecule: instance 在类的末尾声明,在私有部分中。
  • 我尝试了 #2 以及一个解决方案,并在未定义的“myClass::instance”引用中遇到了同样的问题。我确实将 myClass 更改为我正在使用的类。我知道 c++,但这个问题让我陷入了困境。
【解决方案2】:

要传递一个指向方法的指针,它必须是一个静态方法并且你必须指定类名。

试试这个:

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

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

您还应该阅读 Baget 提供的链接,paragraph 33.2 in the C++ FAQ

【讨论】:

    【解决方案3】:

    实际上,C++ 信号处理程序不允许使用 C 和 C++ 中不存在的任何工具(除了在 C++11 中它们可能使用原子),并且必须使用 C 链接。引用 C++11 draft n3242 第 18.10 节“其他运行时支持”[support.runtime](第 8 段),

    C 和 C++ 语言的公共子集由所有声明组成, 可能出现在格式良好的 C++ 程序中的定义和表达式 以及在符合标准的 C 程序中。 POF(“普通旧函数”)是 仅使用来自该公共子集的特征的函数,并且不使用 直接或间接使用任何不是 POF 的函数,除了它 可以使用第 29 条中定义的不是成员函数的函数。全部 信号处理程序应具有 C 链接。可用作信号的 POF 符合标准的 C 程序中的处理程序在以下情况下不会产生未定义的行为 在 C++ 程序中用作信号处理程序。任何其他函数的行为 在 C++ 程序中用作信号处理程序是实现定义的。

    (第 29 条是关于原子的。)

    【讨论】:

      【解决方案4】:
      #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();
       }
      }
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
      【解决方案5】:

      您发布新答案的声誉低于对现有答案发表评论,这似乎很疯狂,但我们开始了。

      gekomad 2015 年 9 月 24 日的回答是我用来解决问题的答案。值得指出的是,只有当只有一个 myClass 实例被创建时,这才会完全有效。否则,静态对象指针将指向可能不是所需的实例之一(最近创建的)。

      而且,如果它对其他人有用,几个答案中链接的常见问题解答问题的有效 2018 年 URL 是:

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

      【讨论】:

        【解决方案6】:

        你可以使用单例模式

            static MyClass &getInstance() {
            static MyClass instance;
            return instance;
        

        【讨论】:

          猜你喜欢
          • 2017-10-25
          • 1970-01-01
          • 1970-01-01
          • 2015-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-05
          相关资源
          最近更新 更多