r-value referenzen für asynchronen callback



  • Huhu,
    Ich arbeite an einer Bibliothek die ein paar wissenschaftliche Berechnungen durchführt.
    Die Bibliothek ist gedacht um mit GUIs benutzt zu werden, die Berechnungen werden also asynchron durchgeführt und in dem GUI oder was auch immer eine Aufgabe an die lib gibt wird zu verschiedenen Anlässen eine übergebene std::function aufgerufen.
    Diese callbacks bekommen immer ein kleines Status-Antwort Objekt, das sieht so aus:

    struct StatusResponse {
            StatusResponse(int respC, std::string respS): responseCode(respC), 
            responseString(std::move(respS)) {};
            int responseCode;
            std::string responseString;
        };
    

    Diese Callbacks sind fire-and-forget, geben nichts zurück (void) und es muss nicht auf den Callback gewartet werden.
    Die StatusResponse Objekte sind also temporär.
    Es scheint nun mehrere Wege zu geben.

    Meine erste Idee war die Callback Funktion wie folgt zu definieren:

    template<typename T0>
        using Action = std::function<void(std::shared_ptr<T0>)>;
    

    Und sie aufzurufen

    rdt::Action<rdt::StatusResponse> callback;
    
        std::shared_ptr<rdt::StatusResponse> response = 
        std::make_shared<rdt::StatusResponse>
        (rdt::errorcode::DEVICE_ID_OUT_OF_RANGE, std::string {"Device ID out 
        of Range!"});
    
        callback(response);
        return;
    

    Das scheint aber ziemlich ineffizient und aufwändig zu sein (Benutzung von std::shared_ptr für fire-and-forget, der callback muss zur aufrufenden Funktion zurückkehren nur um direkt wieder zu returnen...)

    Meine nächste Idee sieht aus wie folgt:

    void callback(std::unique_ptr<StatusResponse> response);
    
        std::unique_ptr<StatusResponse> response = 
        std::make_unique<StatusResponse>(0, "success!");
    
        callback(std::move(response));
    

    Das scheit aber immernoch ineffektiv zu sein, ich baue einen Wrapper um ein Objekt, das sowieso temporär ist.

    Nächste Idee:

    void callback(StatusResponse&& response);
    
        StatusResponse response {0, "Success!"};
        callback(std::move(response));
    

    oder sogar

    callback(StatusResponse {0, "Success!"});
    

    Ich bin nun recht unsicher, welches ich da nehmen soll.

    Deswegen 2 Fragen:
    Ist das std::move im struct Konstruktor sinnvoll?

    Zweite Frage: Welche Lösung wird denn am schnellsten sein? Eine, die ich hier aufliste? Oder doch was ganz anderes?

    Die Callbacks werden etwa so aufgerufen:

    std::thread t(callback, StatusResponse {0, "Success!"});
        t.detach();
    

    Ich habe praktisch erst mit dem Lernen von C++ angefangen, jede Hilfe ist gerne gesehen.

    Ich habe auch einen kleinen Test laufen lassen, die rvalue-reference Variante erzeugt folgende debug Ausgabe:

    Constructor Called!
        Copy Constructor Called!
        Copy Constructor Called!
        Destructor Called!
        Destructor Called!
        Callback called!
        Called callback!
        Exiting caller!
        Exiting callback!
        Destructor Called!
    

    Wenn ich einen move constructor bereitstelle wird der anstatt des Copy Constructors aufgerufen.
    Es scheint recht ineffizient, da das temporäre Objekt 3x zerstört wird...

    Beste Grüße
    NablaSquaredG


Anmelden zum Antworten