VC++11 std::thread Fehler?
-
Mir ist aufgefallen, dass ein Funktionsobjekt, welches von einer Basisklasse erbt, in einem Thread ausgeführt, den falschen operator() aufruft, obwohl er überschrieben wurde.
Folgender Code reproduziert den unerwarteten Effekt.
Ich nehme an, dass das nicht so gewollt ist.#include <iostream> #include <thread> #include <mutex> #include <typeinfo> std::mutex StreamMutex; class Base { public: virtual void operator()() { std::lock_guard <std::mutex> Lock(StreamMutex); std::cout << "Base" << std::endl; } }; class Derived : public Base { public: void operator()() override { std::lock_guard <std::mutex> Lock(StreamMutex); std::cout << "Derived" << std::endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Base* Instance = new Derived(); std::cout << typeid(*Instance).name() << std::endl; (*Instance)(); std::thread Thr(*Instance); Thr.join(); std::cin.get(); return 0; }EDIT: Die Ausgabe:
class Derived
Derived
BaseOder mache ich einen Fehler?
Mir fällt kein Workarond ein...
-
Functors werden kopiert und sind stateless - polymorphes verhalten und state muss gepimpelt werden.
PS:
was ich damit meine: ein functor ist dumm und kann nicht polymorph verwendet werden, weil er immer kopiert wird (und nicht per ref genommen). auch darf er keinen state haben.Deshalb kann man ihm als member einen zeiger auf die eigentliche polymorphe implementierung geben - und der op() leitet dann immer an den polymorphen code weiter. So kann auch state abgebildet werden.
-
Davon erinnere ich mich gelesen zu haben. *Buch rauskram*
-
Du kopierst das Objekt, das ist nachher einfach kein Derived mehr. Ändere zu
std::thread Thr(std::ref(*Instance));
-
Sorry war etwas zu vc lästig..
-
-
probier mal:
std::thread Thr(std::ref(*Instance) );Funktioniert bei mir.
EDIT: Da war cooky451 schneller

-
Solche realen Fälle sind gut für die Aufnahme in die FAQ!
Habe nämlich bisher nie den Sinn für std::ref gesehen, trotz Literatur. Aber dieses Topic hat mein Wissen bereichert.

-
Artchi schrieb:
Solche realen Fälle sind gut für die Aufnahme in die FAQ!
Habe nämlich bisher nie den Sinn für std::ref gesehen, trotz Literatur. Aber dieses Topic hat mein Wissen bereichert.

Ich mag std::ref hier deshalb nicht, weil es so zu leicht ist falschen Code zu schreiben. Denn ein functor ist immer trivial kopierbar - wenn man jetzt hier einen functor hat der anders ist, dann ist es viel zu leicht den doch irgendwo zu kopieren und bämm -> fehlerhafter Code.
-
Artchi schrieb:
Solche realen Fälle sind gut für die Aufnahme in die FAQ!
Habe nämlich bisher nie den Sinn für std::ref gesehen, trotz Literatur. Aber dieses Topic hat mein Wissen bereichert.

Man braucht es auch hier:
std::uniform_real_distribution<double> dist(-200, 200); auto gen = std::bind(dist, Engine::random_number_engine); std::generate(values.begin(), values.end(), std::ref(gen) )Sonst wird jedes mal die selbe Folge von Zufallszahlen generiert
-
Shade Of Mine schrieb:
Ich mag std::ref hier deshalb nicht, weil es so zu leicht ist falschen Code zu schreiben. Denn ein functor ist immer trivial kopierbar - wenn man jetzt hier einen functor hat der anders ist, dann ist es viel zu leicht den doch irgendwo zu kopieren und bämm -> fehlerhafter Code.
std::thread Thr([=]{(*Instance)();});geht auch (glaub'ich)

-
Geht auch mit static_cast, aber man sollte sich bewusst sein, dass das eine völlig andere Bedeutung hat. (Einmal hat man eine Referenz, und einmal wird kopiert.)