Was ist der Unterschied zwischen dem Funktionszeiger, der von std :: function :: target () kommt, und dem normalen Funktionszeiger?

8

Der folgende Code ist eine Signal Implementierung, die mit einer kleinen Änderung aus APUE kopiert wurde

%Vor%

Der obige Code funktioniert gut während meines Tests, aber ich wollte es eher wie einen C ++ - Code machen, also habe ich den Alias ​​von signal_handler in

geändert %Vor%

und auch ich benutze

%Vor%

ersetzen

%Vor%

und jetzt gibt es ein Problem. Ich finde newAction.sa_handler ist immer noch NULL nach

%Vor%

aber ich weiß nicht warum. Kann mir jemand helfen, das zu erklären? Vielen Dank. Hier ist mein Testcode:

%Vor%

Auch wenn ich den Originalcode verwende, wenn ich ihn in Xcode laufe, gibt es keine Ausgabe. Stattdessen führe ich die ausführbare Datei manuell aus, ich kann SIGUSR1 passiert im Terminal sehen. Warum? Wie kann ich die Ausgabe mit Xcode sehen?

    
Sherwin 28.04.2016, 01:20
quelle

2 Antworten

5

Die direkte Antwort ist, dass target() sehr wählerisch ist - Sie müssen es nennen der Typ des Ziels genau , um einen Zeiger darauf zu erhalten, andernfalls erhalten Sie einen Nullzeiger. Wenn Sie Ihr Signal auf usr1_handler setzen, ist das ein -Zeiger für eine Funktion (keine Funktion) - sein Typ ist void(*)(int) , nicht void(int) . Du gibst also target() einfach den falschen Typ. Wenn Sie ändern:

%Vor%

bis

%Vor%

das würde Ihnen das richtige Ziel geben.

Beachten Sie jedoch, was target() tatsächlich zurückgibt:

%Vor%

Es gibt einen Zeiger auf den angegebenen Typ zurück - in diesem Fall wäre das ein void(**)(int) . Sie müssen dies vor der weiteren Zuweisung dereferenzieren. Etwas wie:

%Vor%

Demo .

Die wirkliche Antwort ist jedoch, dass dies wenig Sinn macht. std::function<Sig> ist ein gelöschter Typ, der für die angegebene Sig aufgerufen werden kann - es kann ein Zeiger auf eine Funktion, ein Zeiger auf eine Elementfunktion oder sogar ein umgebendes Funktionsobjekt beliebiger Größe sein. Es ist eine sehr generische Lösung. Aber sigaction akzeptiert nicht irgendeine Art von generischer Callable - sie akzeptiert spezifisch a void(*)(int) .

Durch Erstellen einer Signatur von:

%Vor%

Sie schaffen die Illusion, dass Sie alle aufrufbaren erlauben! Also könnte ich versuchen, etwas wie:

zu übergeben %Vor%

Das ist erlaubt durch Ihre Unterschrift - Ich biete eine aufrufbar an, die ein int benötigt. Aber das Callable ist nicht in einen Funktionszeiger umwandelbar, also ist es nicht etwas, das du an sigaction() weitergeben kannst, also ist das nur ein fehlerhafter Code, der nie funktionieren kann - das ist ein garantierter Laufzeitfehler.

Noch schlimmer, ich könnte etwas übergeben, das in einen Funktionszeiger umgewandelt werden kann, aber vielleicht weiß ich nicht, dass es das ist, was Sie brauchen, also gebe ich Ihnen das Falsche:

%Vor%

Da sigaction() Sie auf Funktionszeiger beschränkt, sollten Sie Ihre Schnittstelle auf Funktionszeiger beschränken. Stark bevorzugen, was Sie vorher hatten. Verwenden Sie das Typsystem, um Fehler abzufangen - verwenden Sie nur Typlöschung, wenn es sinnvoll ist.

    
Barry 30.04.2016, 16:12
quelle
1

Hier ein kleines Beispiel, das Ihnen hilft, die Mechanismen zu verstehen.

%Vor%     
F.bernal 30.04.2016 07:46
quelle

Tags und Links