Ihnen fehlt die Instrumentenkopie- und Verschiebungskonstruktion. Eine einfache Änderung Ihres Programms liefert Hinweise darauf, wo die Konstruktionen stattfinden.
Konstruktor kopieren
#include <iostream>
#include <thread>
#include <functional>
using namespace std;
class tFunc{
int x;
public:
tFunc(){
cout<<"Constructed : "<<this<<endl;
x = 1;
}
tFunc(tFunc const& obj) : x(obj.x)
{
cout<<"Copy constructed : "<<this<< " (source=" << &obj << ')' << endl;
}
~tFunc(){
cout<<"Destroyed : "<<this<<endl;
}
void operator()(){
x += 10;
cout<<"Thread running at : "<<x<<endl;
}
int getX() const { return x; }
};
int main()
{
tFunc t;
thread t1{t};
if(t1.joinable())
{
cout<<"Thread is joining..."<<endl;
t1.join();
}
cout<<"x : "<<t.getX()<<endl;
return 0;
}
Ausgabe (Adressen variieren)
Constructed : 0x104055020
Copy constructed : 0x104055160 (source=0x104055020)
Copy constructed : 0x602000008a38 (source=0x104055160)
Destroyed : 0x104055160
Thread running at : 11
Destroyed : 0x602000008a38
Thread is joining...
x : 1
Destroyed : 0x104055020
Konstruktor kopieren und Konstruktor verschieben
Wenn Sie einen Verschiebungscode angeben, wird dieser für mindestens eine dieser ansonsten Kopien bevorzugt:
#include <iostream>
#include <thread>
#include <functional>
using namespace std;
class tFunc{
int x;
public:
tFunc(){
cout<<"Constructed : "<<this<<endl;
x = 1;
}
tFunc(tFunc const& obj) : x(obj.x)
{
cout<<"Copy constructed : "<<this<< " (source=" << &obj << ')' << endl;
}
tFunc(tFunc&& obj) : x(obj.x)
{
cout<<"Move constructed : "<<this<< " (source=" << &obj << ')' << endl;
obj.x = 0;
}
~tFunc(){
cout<<"Destroyed : "<<this<<endl;
}
void operator()(){
x += 10;
cout<<"Thread running at : "<<x<<endl;
}
int getX() const { return x; }
};
int main()
{
tFunc t;
thread t1{t};
if(t1.joinable())
{
cout<<"Thread is joining..."<<endl;
t1.join();
}
cout<<"x : "<<t.getX()<<endl;
return 0;
}
Ausgabe (Adressen variieren)
Constructed : 0x104057020
Copy constructed : 0x104057160 (source=0x104057020)
Move constructed : 0x602000008a38 (source=0x104057160)
Destroyed : 0x104057160
Thread running at : 11
Destroyed : 0x602000008a38
Thread is joining...
x : 1
Destroyed : 0x104057020
Referenz verpackt
Wenn Sie diese Kopien vermeiden möchten, können Sie Ihren Callable in einen Referenz-Wrapper ( std::ref
) einschließen . Da Sie t
nach dem Einfädeln den Teil verwenden möchten, ist dies für Ihre Situation sinnvoll. In der Praxis müssen Sie beim Threading gegen Referenzen zum Aufrufen von Objekten sehr vorsichtig sein, da die Lebensdauer des Objekts mindestens so lange dauern muss, wie der Thread die Referenz verwendet.
#include <iostream>
#include <thread>
#include <functional>
using namespace std;
class tFunc{
int x;
public:
tFunc(){
cout<<"Constructed : "<<this<<endl;
x = 1;
}
tFunc(tFunc const& obj) : x(obj.x)
{
cout<<"Copy constructed : "<<this<< " (source=" << &obj << ')' << endl;
}
tFunc(tFunc&& obj) : x(obj.x)
{
cout<<"Move constructed : "<<this<< " (source=" << &obj << ')' << endl;
obj.x = 0;
}
~tFunc(){
cout<<"Destroyed : "<<this<<endl;
}
void operator()(){
x += 10;
cout<<"Thread running at : "<<x<<endl;
}
int getX() const { return x; }
};
int main()
{
tFunc t;
thread t1{std::ref(t)}; // LOOK HERE
if(t1.joinable())
{
cout<<"Thread is joining..."<<endl;
t1.join();
}
cout<<"x : "<<t.getX()<<endl;
return 0;
}
Ausgabe (Adressen variieren)
Constructed : 0x104057020
Thread is joining...
Thread running at : 11
x : 11
Destroyed : 0x104057020
Beachten Sie, dass, obwohl ich die Überladungen copy-ctor und move-ctor beibehalten habe, keine aufgerufen wurden, da der Referenz-Wrapper jetzt das zu kopierende / verschobene Objekt ist. nicht das, worauf es sich bezieht. Dieser endgültige Ansatz liefert auch das, wonach Sie wahrscheinlich gesucht haben. t.x
back in main
ist in der Tat modifiziert zu 11
. Es war nicht in den vorherigen Versuchen. Ich kann das jedoch nicht genug betonen: Sei vorsichtig dabei . Die Objektlebensdauer ist kritisch .
Bewegen Sie sich und nichts als
Wenn Sie kein Interesse daran t
haben, wie in Ihrem Beispiel beizubehalten, können Sie die Verschiebungssemantik verwenden, um die Instanz direkt an den Thread zu senden und sich dabei zu bewegen.
#include <iostream>
#include <thread>
#include <functional>
using namespace std;
class tFunc{
int x;
public:
tFunc(){
cout<<"Constructed : "<<this<<endl;
x = 1;
}
tFunc(tFunc const& obj) : x(obj.x)
{
cout<<"Copy constructed : "<<this<< " (source=" << &obj << ')' << endl;
}
tFunc(tFunc&& obj) : x(obj.x)
{
cout<<"Move constructed : "<<this<< " (source=" << &obj << ')' << endl;
obj.x = 0;
}
~tFunc(){
cout<<"Destroyed : "<<this<<endl;
}
void operator()(){
x += 10;
cout<<"Thread running at : "<<x<<endl;
}
int getX() const { return x; }
};
int main()
{
thread t1{tFunc()}; // LOOK HERE
if(t1.joinable())
{
cout<<"Thread is joining..."<<endl;
t1.join();
}
return 0;
}
Ausgabe (Adressen variieren)
Constructed : 0x104055040
Move constructed : 0x104055160 (source=0x104055040)
Move constructed : 0x602000008a38 (source=0x104055160)
Destroyed : 0x104055160
Destroyed : 0x104055040
Thread is joining...
Thread running at : 11
Destroyed : 0x602000008a38
Hier können Sie sehen, dass das Objekt erstellt wird. Der r-Wert-Verweis auf das gleiche Objekt wird dann direkt an gesendet std::thread::thread()
, wo es erneut an seinen endgültigen Ruheplatz verschoben wird, der dem Thread von diesem Punkt an gehört. Es sind keine Kopierer beteiligt. Die tatsächlichen Dtoren sind gegen zwei Schalen und das konkrete Endzielobjekt.