[C++] teure Ressource in Lambda moven

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.

[C++] teure Ressource in Lambda moven

Beitragvon Schrompf » 30.09.2018, 20:41

Hallo,

ich habe mal wieder ein C++-Problem. Ich habe ein Job-System, dem ich beliebige Callables zur Ausführung in diversen Threads übergeben kann. Das sieht in etwa so aus:

Code: Ansicht erweitern :: Alles auswählen
void Dings::MachParallel( std::function<void()>&& func);


Das funktioniert soweit prima, solange ich normale Lambdas verwende. Nun möchte ich aber eine dicke Ressource in das Lambda hinein moven, also dem Lambda den Ownership übergeben. Innerhalb des Lambdas soll das Objekt dann nochmal in eine Funktion gemoved werden. Etwa so:

Code: Ansicht erweitern :: Alles auswählen
auto lambda = [zeugs = std::move(dieRessource)]() mutable { MachWasDamit( std::move( zeugs)); };
dings.MachParallel( std::move( lambda));


Das Lambda muss mutable sein, weil der normale operator() ja eigentlich const wäre und ich die Ressource damit nicht weiterverschieben könnte. Das Problem ist nun, dass ich eine Wand aus Compilerfehlern bekomme, die anscheinend bedeuten, dass std::function irgendwie mein Lambda kopieren will. Und das geht natürlich nicht, weil mein Ressourcen-Objekt nicht kopierbar, sondern nur movable ist.

Zum Ausprobieren gibt hier Beispielcode: https://godbolt.org/z/xxDBIW

Die Frage an die Experten in der Runde lautet: was ist die idiomatische Lösung, um teure Ressourcen mit Ownership an einen Threadworker zu übergeben? Danke im Voraus!
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3759
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: [C++] teure Ressource in Lambda moven

Beitragvon Spiele Programmierer » 30.09.2018, 23:10

Das Problem ist, dass man std::function<> selbst kopieren kann. Und um jetzt die std::function<> kopieren zu können, muss das zugewiesene Lambda natürlich auch kopierbar sein. Das ist nunmal Teil des Interfaces. Du könntest dein Funktionsobject ja z.B. in eine andere Funktion he­r­ein­rei­chen. Spätestens dort kann man ja wirklich nicht mehr wissen, dass man genau dein Funktionsobjekt jetzt nicht kopieren darf.

Da hilft wohl nur std::make_shared beim Zuweisen oder eine eigene Funktionszeigerklasse.

Sonst mir noch ein, man könnte eine Wrapperklasse schreiben wo das Move-Only Objekt z.B. in einem optional<> vorliegt und der Kopierkonstruktor über Move implementiert ist. Das sollte gehen, aber idiomatisch würde ich das nicht nennen. (Und wenn man ganz, ganz, ganz streng ist, auch nicht standardkonform. Was wenn std::function<> intern Kopien anlegen würde?)
Zuletzt geändert von Spiele Programmierer am 01.10.2018, 18:00, insgesamt 1-mal geändert.
Spiele Programmierer
Establishment
 
Beiträge: 345
Registriert: 23.01.2013, 16:55

Re: [C++] teure Ressource in Lambda moven

Beitragvon Schrompf » 01.10.2018, 08:50

Tja, diverse kluge Menschen von StackOverflow sagen das Gleiche wie Du: den Lambda in nen std::shared_ptr moven und den dann als kopierbares Objekt in nen normalen Lambda packen.

Der Hintergrund ist, wie ich gerade erst verstanden habe: std::function<void()> ist ein abstrakter Typ, der muss für alle Instanzen die Eigenschaften festlegen. Und std::function sagt halt: "ich bin kopierbar". Mein Lambda ist nicht kopierbar wegen des nicht kopierbaren Members. std::function kann aber keine Ausnahme für meinen Spezialbruder machen, weil es halt beliebige Funktoren fressen kann. Tja, dumm gelaufen.

Ich werde aber wohl eher ne kleine Cheater-Struktur bauen, die zwar Kopieren erlaubt, aber dann zur Laufzeit asserted oder so. Ich möchte an der Stelle nicht allokieren, weil ich dort kein Lock gebrauchen kann.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3759
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: [C++] teure Ressource in Lambda moven

Beitragvon Spiele Programmierer » 01.10.2018, 17:55

Hast du denn sichergestellt, dass deine std::function<> nicht allokiert?
Die übernimmt Ownership von deinem Lambda und wenn das zu groß ist, wird auch allokiert.
Beim MSVC ab einer Pointergröße und bei Clang/GCC mit libstdc++ ab 2 Pointergrößen im Captureblock. (Quelle: Rumprobieren auf dem Compiler Explorer)

EDIT: Mit make_shared wären es auf Windows also mindestens zwei Allokationen...
Eine typische Zero-Cost Abstraction also. :roll:
Spiele Programmierer
Establishment
 
Beiträge: 345
Registriert: 23.01.2013, 16:55


Zurück zu Programmiersprachen, Quelltext und Bibliotheken

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

cron