c – 从std :: function :: target <>()获取的函数指针与
以下代码是从APUE复制的信号实现,稍作修改
namespace { using signal_handler = void (*)(int); signal_handler signal(sigset_t sig,signal_handler); } Signal::signal_handler Signal::signal(sigset_t sig,void (*handler)(int)) { struct sigaction newAction,oldAction; sigemptyset(&newAction.sa_mask); newAction.sa_flags = 0; newAction.sa_handler = handler; if (sig == SIGALRM) { #ifdef SA_INTERRUPT newAction.sa_flags |= SA_INTERRUPT; #endif } else { newAction.sa_flags |= SA_RESTART; } if (sigaction(sig,&newAction,&oldAction) < 0) throw std::runtime_error("signal error: cannot set a new signal handler.") return oldAction.sa_handler; } 上面的代码在我的测试中运行正常,但我想让它更像C代码,所以我将signal_handler别名更改为 using signal_handler = std::function<void (int)>; 我也用 newAction.sa_handler = handler.target<void (int)>(); 取代 newAction.sa_handler = handler; 现在有一个问题.我发现newAction.sa_handler之后仍然是NULL newAction.sa_handler = handler.target<void (int)>(); 但我不知道为什么.任何人都可以帮我解释一下吗?谢谢. void usr1_handler(int sig) { std::cout << "SIGUSR1 happens" << std::endl; } void Signal::signal_test() { try { Signal::signal(SIGUSR1,usr1_handler); } catch (std::runtime_error &err) { std::cout << err.what(); return; } raise(SIGUSR1); } 即使在Xcode中运行时使用原始代码,也没有输出.相反,我手动运行可执行文件,我可以看到SIGUSR1发生在终端.为什么?如何使用Xcode查看输出? 解决方法
直接的答案是
target() 非常挑剔 – 你必须准确地命名目标的类型以获得指向它的指针,否则你得到一个空指针.当你将信号设置为usr1_handler时,这是一个指向函数(不是函数)的指针 – 它的类型是void(*)(int),而不是void(int).所以你只是给target()提供了错误的类型.如果你改变:
handler.target<void (int)>(); 至 handler.target<void(*)(int)>(); 这会给你正确的目标. 但请注意target()实际返回的内容: template< class T > T* target(); 它返回一个指向所提供类型的指针 – 在这种情况下,它将是一个void(**)(int).在进一步分配之前,您需要取消引用.就像是: void(**p)(int) = handler.target<void(*)(int)>(); if (!p) { // some error handling } newAction.sa_handler = *p; Demo. 然而,真正的答案是这样做没有多大意义.的std ::功能<西格>是给定Sig可擦除的类型 – 它可以是指向函数的指针,指向成员函数的指针,甚至是任意大小的包装函数对象.这是一个非常通用的解决方案.但sigaction不接受任何类型的泛型可调用 – 它特别接受void(*)(int). 通过创建签名: std::function<void(int)> signal(sigset_t sig,std::function<void(int)> ); 你正在创造一种你允许任何可赎回的错觉!所以,我可能会尝试传递类似的东西: struct X { void handler(int ) { ... } }; X x; signal(SIGUSR1,[&x](int s){ x.handler(s); }); 这是你的签名所允许的 – 我提供了一个带有int的可调用.但是那个callable不能转换为函数指针,所以它不是你可以传递给sigaction()的东西,所以这只是错误的代码永远无法工作 – 这是一个保证运行时失败. 更糟糕的是,我可能会传递一些可转换为函数指针的东西,但可能不知道那就是你需要的东西,所以我给你错了: // this will not work,since it's not a function pointer signal(SIGUSR1,[](int s){ std::cout << s; }); // but this would have,if only I knew I had to do it signal(SIGUSR1,+[](int s){ std::cout << s; }); 由于sigaction()将您限制为仅仅是函数指针,因此您应该将接口限制为仅仅是函数指针.非常喜欢你以前拥有的东西.使用类型系统来捕获错误 – 只在有意义时才使用类型擦除. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |