Verwirrung mit move-Constructor und std::thread
-
Servus,
#include <iostream> #include <string> #include <thread> class A { public: A() { } A(A const &rhs) { std::cout << "A(A const &rhs)\n"; } A(A&& rhs) { std::cout << "A(A&& rhs)\n"; } }; void foo(A a) { std::cout << "foo()\n"; } int main() { A a; std::thread t(&foo, std::move(a)); t.join(); return 0; }
Ausgabe:
A(A&& rhs) A(A&& rhs) A(A&& rhs) A(A&& rhs) A(A const &rhs) foo()
- Wieso wird der move-Konstruktor 4mal aufgerufen?
- Wieso wird der copy-Konstruktor aufgerufen? Wie kann ich das verhindern?
Schonmal danke ..
-
@2) Der simpelste Weg, das verhindern wäre ihn zu deleten (oder halt zu verstecken/nicht implementieren)
-
Wenn ich das mache bekomme ich einen Fehler vom Compiler. Was aber eigentlich auch logisch ist, da foo() den Paramater by-value nimmt und nicht der dazugehörige Copy-constructor gefunden werden kann, oder?
Dann verstehe ich aber nicht mehr den Sinn von der move-Semantik, und erst recht nicht wieso der Move-constructor 4mal vorher aufgerufen wird ...
-
std::forward, std::ref und std::cref sind deine Freunde.
Edit: Doch nicht.
-
A(A&& rhs) A(A&& rhs) A(A&& rhs) A(A&& rhs) A(A const &rhs) foo()
Dein Compiler unterstützt C++11 noch nicht ganz. Den Kopierkonstruktor hier aufzurufen ist gar nicht erlaubt, der Typ könnte ja Move-Only sein.
Der GCC gibt hier aus:
A(A&& rhs) A(A&& rhs) A(A&& rhs) foo()
-
Und der dreimalige Aufruf des Move-Konstruktors liegen an der GCC-Implementierung von std::thread.
-
Nathan schrieb:
Und der dreimalige Aufruf des Move-Konstruktors liegen an der GCC-Implementierung von std::thread.
Wieso es genau drei sind verstehe ich nicht.
Eigentlich brauchts doch nur 2: 1x move um A in std::thread zu speichern und 1x um Foo aufzurufen.
-
Ok, das würde es erklären.
Ich benutze Visual Studio 2013 Professional, ich dachte der Compiler würde das mittlerweile unterstützen?
-
htasaed schrieb:
Nathan schrieb:
Und der dreimalige Aufruf des Move-Konstruktors liegen an der GCC-Implementierung von std::thread.
Wieso es genau drei sind verstehe ich nicht.
Eigentlich brauchts doch nur 2: 1x move um A in std::thread zu speichern und 1x um Foo aufzurufen.
Soweit ich jetzt auf die Schnelle den Sourecode verstehe:
Der Konstruktor ruft std::__bind_simple mit den Argumenten auf.
std::__bind_simple erzeugt ein Objekt was vom Typ std::_Bind_simple ist.
std::_Bind_simple speichert die Argumente und den Funktionspointer in einem tuple, daher wohl der zusätzliche move.