K
shft schrieb:
Ich habe ein Thread, wobei seine Parameter beim Start kopiert bzw. verschoben werden müssen, da evtl. sonst die Lebenszeit des Threads, welcher diesen Thread startet, nicht lang genug ist. Um es dem Nutzer freizustellen, welche Version er nutzen möchte, benötige ich eine Version, die entscheidet, ob kopiert oder verschoben werden soll.
Dafür brauchst du gar keine zwei Versionen. Das Kopieren/Moven machst nicht Du sondern der Nutzer bzw die thread-Library selbst. Der Parameter-Typ den, du für deine Funktion wählst, die du in einem neuen Thread ausführst, ist davon nahezu unabhängig.
shft schrieb:
void foo( const std::string& s )
{
foo( std::move( std::string( s ) ) );
}
Das std::move ist hier überflüssig, da std::string(s) ja eh schon ein Rvalue ist.
shft schrieb:
/*
Problem:
Möchte ich den String in der Funktion nochmals verschieben o.Ä.,
also muss ich nochmals std::move [...]
*/
Du willst also einen eigenen std::string in der Funktion haben? Dann nimm doch einfach
void foo(std::string meineigenerstring) {
…
}
Ob das Ding kopiert oder gemoved wird, hängt davon ab, ob der Aufrufer std::thread bzw std::async einen Lvalue-string oder Rvalue-string übergibt. Und da wir wissen, dass std::string einen sehr effizienten Move-Konstruktor hat, können wir uns hier auch die Sache mit der Überladung sparen. Das einzige, was wir uns damit sparen würden, wäre nämlich ein Move, aber der ist ja billig bei std::string .
Und auch wenn Du das hier schreibst:
void foo(const std::string& constref) {
…
}
musst Du dir keine Sorgen über Lebenszeiten machen, weil bei Aufrufen wie
std::thread (foo, std::string("temp"));
std::thread die Argumente immer in den anderen Thread kopiert/moved. Wenn Du einem neuen Thread explizit eine Referenz übergeben willst, ginge das so:
void foo(std::string& nonconstref) {
nonconstref = "blupp";
}
int main() {
string blah;
std::thread t (foo, std::ref(blah));
t.join();
std::cout << blah << std::endl;
}
Man muss hier also extra std::ref hinschreiben, damit der string nicht gemoved oder kopiert wird.
Wenn Dir das nicht ganz geheuer ist, kannst du das natürlich auch per Lambda-Ausdruck machen. Dann klappt das mit der Überladung eh besser, falls Du sowas wirklich willst:
void foo(std::string meins) {
…
}
int main() {
string blah = "hello world";
std::thread t ( [blah = move(blah)] { foo(move(blah)); } ); // C++14
t.join();
}
Der String zieht zunächst in das Lambda-Objekt um, welches dann in den neuen Thread umzieht und dann den string weiter an foo übergibt ohne irgendwo den string jemals zu kopieren. Aber das ist wirklich äquivalent zu
void foo(std::string meins) {
…
}
int main() {
string blah = "hello world";
std::thread t (foo, move(blah));
t.join();
}
Der einzige Vorteil, den Dir hier ein Lambda-Ausdruck bietet, ist, dass Du damit besser klarkommst, wenn foo tatsächlich überladen wurde.
HTH
kk