Hallo Community,
ich hänge aktuell an einem kleinen Cast Problem. Vielleicht kann mir da
ein C++ Spezialist mal kurz helfen:
void test()
{
void* x = NULL;
vector<MyClass*> myClassList;
myClassList.push_back(new MyClass());
vector<void*> myList;
myList.push_back(&myClassList);
x = &myList;
vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);
vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>
*>(cast1[0]);
cout << cast2.size();
}
Für cast2 kommt komischerweise 0 heraus obwohl ein Element drin sein
müsste. Habe ich irgendwo einen Leichtsinsfehler beim casten gemacht?
Danke schonmal,
IngC++
Peter II schrieb:> bin mir jetzt nicht ganz sicher, aber die vectoren werden hier> noch mal kopiert.vector<MyClass*> cast2 => reinterpret_cast<vector<MyClass*>> *>(cast1[0]);>> sicher das du das willst?> mit einem Typedef könnte man das auch lesbarer schreiben.
Ich nutze einen C++ 99 Compiler. Da muss ich explizit den Datentyp
vornedran schreiben, bei C++ 11 Compiler kann man das auto Keyword
benutzen.
Aber du hast recht, mit typedefs wäre das ganze lesbarer. Dennoch bleibt
mein Problem bestehen...
damit es nicht ganz nutzlos ist.
Da fehlt ein * bei
reinterpret_cast<std::vector<myClass*> *>(cast1[0]);
du castest ja auf einen Zeiger. Den musst du natürlich auch
dereferenzieren.
Mikro 7. schrieb:> #include <iostream>> #include <vector>>> struct MyClass { } ;>> using namespace std ;>> void test()> {> void* x = NULL;>> vector<MyClass*> myClassList;> myClassList.push_back(new MyClass());>> vector<void*> myList;> myList.push_back(&myClassList);>> x = &myList;>> vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);>> vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>> *>(cast1[0]);>> cout << cast2.size();> }>> $ g++ -Wall -c test.cc> test.cc: In function ‘void test()’:> test.cc:22:74: error: conversion from ‘std::vector<MyClass*>*’ to> non-scalar type ‘std::vector<MyClass*>’ requested> vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>> *>(cast1[0]);
Sorry, Tippfehler (hab den Derefenzierungsoperator vor dem reinterpret
hier vergessen gehabt, im Code steht er jedoch)
Mit
vector<MyClass*> cast2 = *reinterpret_cast<vector<MyClass*>
> *>(cast1[0]);
Sollte es zwar bauen, aber das Problem mit dem ursprünglichen Vektor
besteht weiterhin. Trotzdem danke schonmal
nicht"Gast" schrieb:> damit es nicht ganz nutzlos ist.> Da fehlt ein * bei> reinterpret_cast<std::vector<myClass*> *>(cast1[0]);>> du castest ja auf einen Zeiger. Den musst du natürlich auch> dereferenzieren.
Ja danke, war nur ein Schreibfehler meinerseits. Im Originalcode hatte
ich es nicht vergessen. Trotzdem gut aufgepasst :-)
Hm komisch, ich könnte schwören das es bei mir heute nicht geklappt hat.
Ich Check morgen nochmal meinen Code und Berichte. Danke schonmal für
deine Hilfe!
IngC++ schrieb:> Ich nutze einen C++ 99 Compiler
Was ist denn C++99? Ich kenne nur C++98, C++03, 11, 14 und 17...
Dass so ein Code fürchterlich mies ist sollte klar sein. Die MyClass
Instanz wird nicht freigegeben (Speicherleck). Statt NULL sollte man
nullptr schreiben. reinterpret_cast ist nur selten notwendig (wenn schon
in low-level Code für I/O und Speicherverwaltung) und meistens ein Indiz
für schlechtes Design.
Dr. Sommer schrieb:> IngC++ schrieb:> Ich nutze einen C++ 99 Compiler>> Was ist denn C++99? Ich kenne nur C++98, C++03, 11, 14 und 17...> Dass so ein Code fürchterlich mies ist sollte klar sein. Die MyClass> Instanz wird nicht freigegeben (Speicherleck). Statt NULL sollte man> nullptr schreiben. reinterpret_cast ist nur selten notwendig (wenn schon> in low-level Code für I/O und Speicherverwaltung) und meistens ein Indiz> für schlechtes Design.
1. Tippfehler, meinte auch C++ 98.
2. Das war nur kleines Snippet welches die Problematik aufzeigen sollte.
Selbstverständlich habe ich mich im Originalcode um Memory Leaks
gekümmert.
3. Warum ist das ein Indiz für schlechtes Design? Sorry für meine
Unwissenheit - komme aus der Managed Welt und hab bisher fürs Casten in
C++ entweder Boxed, static_cast oder reinterpret_cast verwendet. Gerne
lasse ich mich von einem besseren Weg überzeugen.
IngC++ schrieb:> Warum ist das ein Indiz für schlechtes Design?
reinterpret_cast umgeht halt die Prüfungen des Compilers
(Typsicherheit). Damit ist es sehr einfach, schwer zu findende Fehler
einzubauen.
u.a. durch Verwendung von templates und "sauberen" Klassen-Strukturen
lässt sich das (fast) immer vermeiden, was typischerweise auch zu besser
strukturierten und lesbaren Code führt. reinterpret_cast ist oft eine
"schmutzige" Abkürzung, deswegen ist diese Anweisung auch so lang und
hässlich ;-)
IngC++ schrieb:> C++ entweder Boxed, static_cast oder reinterpret_cast verwendet.
Boxed bei C++/CLI oder was meinst du? Du kannst ja mal deine typischen
Fälle für reinterpret_cast zeigen, dann lässt sich bestimmt eine bessere
Lösung finden.
IngC++ schrieb:> Nebenbei bemerkt gibt es nullptr erst ab C++ 11. Ich nutze C++ 98,> von> daher bin ich etwas eingeschränkter.
Das ist schade - C++11 bringt viele sehr nützliche Verbesserungen,
insbesondere auch für den Embedded Bereich. nullptr ist eine davon,
damit lassen sich Uneindeutigkeiten/Fehler in bestimmten Sonderfällen
vermeiden.
Wenn du viel C++ nutzen möchtest solltest du dir Gedanken machen ob du
nicht einen modernen Compiler nutzen kannst, welcher C++11 beherrscht.
IngC++ schrieb:> Für cast2 kommt komischerweise 0 heraus obwohl ein Element drin sein> müsste. Habe ich irgendwo einen Leichtsinsfehler beim casten gemacht?
Und weil es noch niemand erwähnt hat: von void* auf andere Zeiger-Typen
reicht in C++ static_cast.
IngC++ schrieb:> 3. Warum ist das ein Indiz für schlechtes Design?
weil du den Vektor kopierst. Verwende lieber eine Referenz darauf. Nur
für den Cast eine Kopie von allem anzulegen ist sinnlos.
IngC++ schrieb:> 3. Warum ist das ein Indiz für schlechtes Design? Sorry für meine> Unwissenheit - komme aus der Managed Welt und hab bisher fürs Casten in> C++ entweder Boxed, static_cast oder reinterpret_cast verwendet. Gerne> lasse ich mich von einem besseren Weg überzeugen.
Bei C++ wurde sehr viel Arbeit reingesteckt, dass man weitgehend ohne
Casts auskommt. Immer wenn du einen Cast benötigst, solltest du erstmal
überlegen, ob es nicht einen Weg ohne den Cast gibt. Der ist meistens
der sauberere Weg. Wie schon gesagt wurde, ist vor allem für den
reinterpret_cast lowlevel-Code, der direkt mit irgendwelcher Hardware
bzw. Byte-orientierten Schnittstellen arbeitet, der
Hauptanwendungszweck.
IngC++ schrieb:> Hallo Community,>> ich hänge aktuell an einem kleinen Cast Problem. Vielleicht kann mir da> ein C++ Spezialist mal kurz helfen:>> void test()> {> void* x = NULL;>> vector<MyClass*> myClassList;> myClassList.push_back(new MyClass());>> vector<void*> myList;> myList.push_back(&myClassList);>> x = &myList;>> vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);>> vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>> *>(cast1[0]);>>> cout << cast2.size();>>> }>> Für cast2 kommt komischerweise 0 heraus obwohl ein Element drin sein> müsste. Habe ich irgendwo einen Leichtsinsfehler beim casten gemacht?
Warum verwendest Du bei der Definition von
1
vector<void*>myList;
nicht den richtigen DT?
Abgesehen davon, dass das ganze abenteuerlich ist ...
Wilhelm M. schrieb:> nicht den richtigen DT? Abgesehen davon, dass das ganze abenteuerlich> ist ...
Vermutlich soll das ganze spaeter Polymorphismus emulieren...
lalala schrieb:> Wilhelm M. schrieb:>> nicht den richtigen DT? Abgesehen davon, dass das ganze abenteuerlich>> ist ...>> Vermutlich soll das ganze spaeter Polymorphismus emulieren...
Vermutlich war es nur ein Beispiel?
Torsten R. schrieb:> lalala schrieb:>> Wilhelm M. schrieb:>>> nicht den richtigen DT? Abgesehen davon, dass das ganze abenteuerlich>>> ist ...>>>> Vermutlich soll das ganze spaeter Polymorphismus emulieren...>> Vermutlich war es nur ein Beispiel?
Vermute mal: Unwissenheit, dass man vectors of vectors of maps of ...
machen kann.
Sebastian V. schrieb im Beitrag #5026933:
> Torsten R. schrieb:>> Vermutlich war es nur ein Beispiel?>> Hoffentlich ein Beispiel wie man es auf keinen Fall machen sollte. Es> gibt keine Garantie das ein vector<MyClass*> und vector<void*> irgendwie> vom Datenlayout kompatibel sind und das bei dem Cast irgendwas> sinnvolles bei rum kommt.
Stimmt, und wenn Du Dir den Beispiel-Code mal genauer durchließt, dann
wirst Du sehen, dass der Kollege das auch überhaupt nicht probiert hat.
Sebastian V. schrieb:> Ja habs auch gerade gesehen...
Solange er die Frage nicht beantwortet, warum er jegliche Typinformation
explizit wegwirft bei der Definition von myList ist jede Spekulation
überflüssig. Den (fragwürdigen) Grund kann nur TO mitteilen...
Erstmal danke für eure konstruktiven Beiträge. Grund für dieses
fragwürdige Konstrukt ist das Arbeiten mit Threads Bzw. CreateThread.
Diesem kann man meines Wissens als Argument nur einen void* mitgeben.
Und da ich mehrere Argumente unterschiedlichen Datentyps übergeben muss
packe ich diese in eine Liste von void* und caste die Elemente im Thread
auf die gewünschten Typen zurück.
Bin aber gerne für Vorschläge offen :-)
IngC++ schrieb:> Bin aber gerne für Vorschläge offen :-)
Ok, es besteht aber trotzdem kein Grund, den Container "falsch" zu
typisieren ...
Willst Du pthreads verwenden? Macht auch wenig Sinn.
Wir haben mittlerweile mehr als C++11 und damit
http://en.cppreference.com/w/cpp/thread
Da ich ahne welche Beiträge kommen werden schonmal vornweg: Ja man kann
auch ein struct oder eine Klasse mit den Inhalten definieren und deren
Referenz per void* an den Thread übergeben. Wäre auch sauberer an der
Stelle, bin da grad aber erst am ausprobieren welches die eleganteste
Lösung wäre.
Unabhängig von der Thread Geschichte möchte ich an einer anderen Stelle
Polymorphismus "emulieren", d.h ich habe eine Liste von Instanzen die
das gleiche "Interface" (in C++ habe ich das durch abstrakte Klassen mit
pure Virtual Methods gelöst) besitzen und deren Methode einen void* als
Argument erwarten. Jedes Interface kann aber eine andere konkretere
Implementierung der Methode haben, so dass es nicht einen speziellen
Datentyp gibt der übergeben werden kann sondern je nach Kontext ein
anderer. Alternativ könnte man auch die Methoden mit den Datentypen
überladen, nur habe ich dann bei manchen konkreten Implementierungen
überladene Methoden zu implementieren die gar nicht gebraucht werden.
Wilhelm M. schrieb:> IngC++ schrieb:>> Bin aber gerne für Vorschläge offen :-)>> Ok, es besteht aber trotzdem kein Grund, den Container "falsch" zu> typisieren ...> Willst Du pthreads verwenden? Macht auch wenig Sinn.> Wir haben mittlerweile mehr als C++11 und damit> http://en.cppreference.com/w/cpp/thread
Hallo Wilhelm,
aufgrund bestimmter OS Anforderungen bin ich leider an C++ 98 gebunden,
auch wenn ich selber gerne C++ 11 nehmen möchte. Ich benutze aktuell
CreateThreads.
IngC++ schrieb:> Unabhängig von der Thread Geschichte möchte ich an einer anderen Stelle> Polymorphismus "emulieren", d.h ich habe eine Liste von Instanzen die> das gleiche "Interface" (in C++ habe ich das durch abstrakte Klassen mit> pure Virtual Methods gelöst) besitzen und deren Methode einen void* als> Argument erwarten. Jedes Interface kann aber eine andere konkretere> Implementierung der Methode haben, so dass es nicht einen speziellen> Datentyp gibt der übergeben werden kann sondern je nach Kontext ein> anderer. Alternativ könnte man auch die Methoden mit den Datentypen> überladen, nur habe ich dann bei manchen konkreten Implementierungen> überladene Methoden zu implementieren die gar nicht gebraucht werden.
Hört sich nach double-dispatch an.
IngC++ schrieb:> Wilhelm M. schrieb:> IngC++ schrieb:> Bin aber gerne für Vorschläge offen :-)> Ok, es besteht aber trotzdem kein Grund, den Container "falsch" zu> typisieren ...> Willst Du pthreads verwenden? Macht auch wenig Sinn.> Wir haben mittlerweile mehr als C++11 und damit> http://en.cppreference.com/w/cpp/thread>> Hallo Wilhelm,>> aufgrund bestimmter OS Anforderungen bin ich leider an C++ 98 gebunden,> auch wenn ich selber gerne C++ 11 nehmen möchte. Ich benutze aktuell> CreateThreads.
OS Anforderungen war jetzt das falsche Wort - nennen wir es
Rahmenbedingungen. Klar könnte man rein theoretisch C++ 11 nehmen und
die Runtime dazu mitliefern, aber das ist aktuell nicht gewollt.
Wilhelm M. schrieb:> IngC++ schrieb:>> Unabhängig von der Thread Geschichte möchte ich an einer anderen Stelle> Polymorphismus "emulieren", d.h ich habe eine Liste von Instanzen die> das gleiche "Interface" (in C++ habe ich das durch abstrakte Klassen mit> pure Virtual Methods gelöst) besitzen und deren Methode einen void* als> Argument erwarten. Jedes Interface kann aber eine andere konkretere> Implementierung der Methode haben, so dass es nicht einen speziellen> Datentyp gibt der übergeben werden kann sondern je nach Kontext ein> anderer. Alternativ könnte man auch die Methoden mit den Datentypen> überladen, nur habe ich dann bei manchen konkreten Implementierungen> überladene Methoden zu implementieren die gar nicht gebraucht werden.>> Hört sich nach double-dispatch an.
Exakt das ist es.
IngC++ schrieb:> Unabhängig von der Thread Geschichte möchte ich an einer anderen Stelle> Polymorphismus "emulieren", d.h ich habe eine Liste von Instanzen die> das gleiche "Interface" (in C++ habe ich das durch abstrakte Klassen mit> pure Virtual Methods gelöst) besitzen und deren Methode einen void* als> Argument erwarten. Jedes Interface kann aber eine andere konkretere> Implementierung der Methode haben, so dass es nicht einen speziellen> Datentyp gibt der übergeben werden kann sondern je nach Kontext ein> anderer. Alternativ könnte man auch die Methoden mit den Datentypen> überladen, nur habe ich dann bei manchen konkreten Implementierungen> überladene Methoden zu implementieren die gar nicht gebraucht werden.
Das würde ich aber für die Polymorphistik (es heißt übrigens
Polymorphie) auf jeden Fall gegenüber einem void* vorziehen. Warum
werden denn nicht alle gebraucht? Könnte man vielleicht in der
Basisklasse eine default-Implementation anbieten? Was soll passieren,
wenn versehentlich mal eine der "nicht gebrauchten" Kombinationen doch
vorkommt? Evtl. lässt sich auch mit Templates was machen. Ist halt
schwierig zu sagen, aber bei einem void* für sowas gehen bei mir alle
roten Lampen an.
IngC++ schrieb:> Wilhelm M. schrieb:>> IngC++ schrieb:>>>> Unabhängig von der Thread Geschichte möchte ich an einer anderen Stelle>> Polymorphismus "emulieren", d.h ich habe eine Liste von Instanzen die>> das gleiche "Interface" (in C++ habe ich das durch abstrakte Klassen mit>> pure Virtual Methods gelöst) besitzen und deren Methode einen void* als>> Argument erwarten. Jedes Interface kann aber eine andere konkretere>> Implementierung der Methode haben, so dass es nicht einen speziellen>> Datentyp gibt der übergeben werden kann sondern je nach Kontext ein>> anderer. Alternativ könnte man auch die Methoden mit den Datentypen>> überladen, nur habe ich dann bei manchen konkreten Implementierungen>> überladene Methoden zu implementieren die gar nicht gebraucht werden.>>>> Hört sich nach double-dispatch an.>> Exakt das ist es.
Und warum machst Du es dann nicht so?
Andere Frage: musst Du wirklich einen void* Parameter an CreateThread
übergeben? Sprich: arbeiten die Threads mit Kopien der Daten?
Falls nicht, kann Du gleich ein gemeinsam-genutztes globales Objekt
anlegen, auf das alle Thread zugreifen (Achtung: Synchronisation).
Zeig doch mal einen typischen Aufruf, wie die virtuelle Methode mit dem
void* aufgerufen wird. Ich habe das Gefühl, wenn du weißt welchen
Datentyp du übergeben musst, weißt du auch, um welche konkrete Klasse es
sich handelt...?
In C++11 gibt es std::thread, da musst du nix nach void* casten... Wenn
ein Compiler für C++11 vorhanden ist (zB Microsoft Visual C++, GCC,
Clang, ARMCC...) sollte es normalerweise kein Problem sein einfach auf
C++11 umzustellen. Da muss man eigentlich nichts an einer "Runtime"
ändern. C++ ist ja auch abwärts-kompatibel. Es gibt eigentlich wenig
Grund sich an so alte Technik zu binden!
@Wilhelm M.
>Andere Frage: musst Du wirklich einen void* Parameter an CreateThread>übergeben? Sprich: arbeiten die Threads mit Kopien der Daten?
muss er - aber wie du bei void* auf "Kopie" kommst musst du noch mal
erklären
>Falls nicht, kann Du gleich ein gemeinsam-genutztes globales Objekt>anlegen, auf das alle Thread zugreifen (Achtung: Synchronisation).
ist doch alles völlig unnötig wenn man es richtig macht - immer diese
komischen Tips
@IngC++
mach einfach eine saubere Datenklasse - und lass das mit dem vector
da steckst du alle PODs/Vectoren als Kopie/Referenzen/Pointer usw. rein
die du brauchst
und dann ist es doch nur
DatenKapselKlasse daten;
CreateThread((void*)&daten)
oder
DatenKapselKlasse daten = new DatenKapselKlasse(...);
CreateThread((void*)daten)
und in deiner ThreadProc nur
DatenKapselKlasse& daten = *(DatenKlasse*)void_parameter;
ich verstehe absolut nicht warum du dafür so wirren vector<void*> Code
schreiben musst - das ist unübersichtlich und höchst fehleranfällig und
einfach grundlos
Dr. Sommer schrieb:> Zeig doch mal einen typischen Aufruf, wie die virtuelle Methode mit dem> void* aufgerufen wird. Ich habe das Gefühl, wenn du weißt welchen> Datentyp du übergeben musst, weißt du auch, um welche konkrete Klasse es> sich handelt...?>> In C++11 gibt es std::thread, da musst du nix nach void* casten...
Das habe ich oben doch schon geschrieben! Überlesen? Das will er nicht!
Bert3 schrieb:> @Wilhelm M.>>>Andere Frage: musst Du wirklich einen void* Parameter an CreateThread>>übergeben? Sprich: arbeiten die Threads mit Kopien der Daten?
Du hast das gar nicht verstanden!
Die Frage ist: muss er wirklich mit gem. DS arbeiten oder kann er auch
Kopien (ggf. CoW) benutzen.
Bert3 schrieb:>> DatenKapselKlasse daten = new DatenKapselKlasse(...);> CreateThread((void*)daten)>> und in deiner ThreadProc nur> DatenKapselKlasse& daten = *(DatenKlasse*)void_parameter;>
Oder er schreibt ein Singleton oder Monostate, dann kann er ganz auf die
casts und die Zeiger verzichten (Achtung: Singleton aber richtig machen,
sprich für Nebenläufigkeit).
Bert3 schrieb:> @Wilhelm M.>>>Andere Frage: musst Du wirklich einen void* Parameter an CreateThread>>übergeben? Sprich: arbeiten die Threads mit Kopien der Daten?>> muss er - aber wie du bei void* auf "Kopie" kommst musst du noch mal> erklären>>>Falls nicht, kann Du gleich ein gemeinsam-genutztes globales Objekt>>anlegen, auf das alle Thread zugreifen (Achtung: Synchronisation).>> ist doch alles völlig unnötig wenn man es richtig macht - immer diese> komischen Tips
Quatsch: klar braucht er Synchronisation. Ein std::vector<> ist
unsynchronisiert.
Wilhelm M. schrieb:>>>> DatenKapselKlasse daten;>> CreateThread((void*)&daten)>> Wenn das ne lokale Variable ist, ist es schon falsch!!!
solange er den Scope vor Thread-Ende nicht verlaesst ist da nichts
falsch - kommt darauf an was/wie er macht
>Oder er schreibt ein Singleton oder Monostate, dann kann er ganz auf die>casts und die Zeiger verzichten (Achtung: Singleton aber richtig machen,>sprich für Nebenläufigkeit).
warum soll er dafür ein Singleton oder Monotstate verwenden - wenn er x
Threads mit unterschiedlichen Daten füllt ist das nix - und die
verwendung von den Daten in einem Thread sind jetzt auch nicht sooo
besonders das man dafür Sonder-Verwaltungen braucht - er muss eben nur
darauf Achten das seine Variablen den Thread-Lauf ueberdauern
Bert3 schrieb:> Wilhelm M. schrieb:>>>>>> DatenKapselKlasse daten;>>> CreateThread((void*)&daten)>>>> Wenn das ne lokale Variable ist, ist es schon falsch!!!>> solange er den Scope vor Thread-Ende nicht verlaesst ist da nichts> falsch - kommt darauf an was/wie er macht
Genau! Deswegen ist sowas fehlerträchtig und sollte man nicht machen!
Wilhelm M. schrieb:> Quatsch: klar braucht er Synchronisation. Ein std::vector<> ist> unsynchronisiert.
nur wenn er schreibend zugreift - davon hat er nichts geschrieben
btw: was ist mit void* und der Kopie von der du gesprochen hast
>Genau! Deswegen ist sowas fehlerträchtig und sollte man nicht machen!
ein Singleton bring einen Globalen Zustand rein - sollte er mit vielen
Threads und unterschiedlichen Daten hantieren ist das genau so blöd
kommt definitiv nur auf seinen Anwendungsfall an
aber er hat sowieso keine Probleme mit dem Scope - er will nur komischen
direkt einen vector auf void* cast und damit arbeiten
meine (Thread)DatenKapselung macht die Sache nur sauber und ob das dann
auf dem Stack, Heap oder in einem Singleton drinn steckt ist ein anderer
ganz Stiefel
Datenkapselung(was nutzt der Thread wenn es z.B. auch nur Referenzen
sind) und Lifetime Management der Daten (Stack, Heap, "Singleton") sind
2 paar Stiefel
Bert3 schrieb:>>Genau! Deswegen ist sowas fehlerträchtig und sollte man nicht machen!>> ein Singleton bring einen Globalen Zustand rein - sollte er mit vielen> Threads und unterschiedlichen Daten hantieren ist das genau so blöd
Nein, es gibt keine dangling-pointer -> großer Unterschied!!!
Globaler Zustand: das schreibe ich doch die ganze Zeit: Kopien oder
nicht für die Threads. Das wissen wir nicht ...
Der Thread muss 0 Ahnung davon haben voher sein Daten kommen - daher die
DatenKapsel-Klasse - wie das dann Ausserhalb verwaltet wird muss der
Thread-Proc 100% egal sein, ein Singleton zum leichten Zugriff ist hier
definitiv nicht nötig weil es einfach trivial ist die Daten in den
Thread zu bekommen, und globale und Threads sind meistens auch eine
Krücke mit ihren ganz eigenen Problemen (x Threas, n Daten)
Bert3 schrieb:> Der Thread muss 0 Ahnung davon haben voher sein Daten kommen - daher die> DatenKapsel-Klasse -
Dagegen habe ich doch gar nichts ...
> wie das dann Ausserhalb verwaltet wird muss der> Thread-Proc 100% egal sein,
Und deswegen sollte kein Abhängigkeit eingebaut werden, die Du mit der
Variante der lokalen Variablen eben bekommst.
> ein Singleton zum leichten Zugriff ist hier> definitiv nicht nötig weil es einfach trivial ist die Daten in den> Thread zu bekommen, und globale und Threads sind meistens auch eine> Krücke mit ihren ganz eigenen Problemen (x Threas, n Daten)
entweder hat man gem. DS oder nicht. Wenn die Threads mit Kopien
auskommen, ist ja alles gut, aber das wissen wir nicht ...
>Nein, es gibt keine dangling-pointer -> großer Unterschied!!!
wo soll denn da ein dangling-pointer herkommen?
Singleton + Thread ist eine scheinbar einfache Lösung für ein
nicht-existentes Problem das noch mehr Probleme macht - egal wie die
reale Situation bei IngC++ ist
Bert3 schrieb:>>Nein, es gibt keine dangling-pointer -> großer Unterschied!!!>> wo soll denn da ein dangling-pointer herkommen?
Immer noch nicht kapiert? Der Code ist nicht refaktorierungsfest!
Bert3 schrieb:>>Nein, es gibt keine dangling-pointer -> großer Unterschied!!!>> wo soll denn da ein dangling-pointer herkommen?>> Singleton + Thread ist eine scheinbar einfache Lösung für ein> nicht-existentes Problem
Das Problem liegt offenbar vor!
> das noch mehr Probleme macht
Wo? Welche?
> - egal wie die> reale Situation bei IngC++ ist
Die wir gar nicht kennen ...!!!
>Das Problem liegt offenbar vor!
Wo schreibt er das? er hat nur ein Problem mit einem trivial-cast - den
ich vermeiden würden
>>das noch mehr Probleme macht>Wo? Welche?
wenn du n Threads mit m Daten hast - bekommst du entweder
n Singletons oder ein Singleton das n verwalten kann
=> Locking, Daten-Reset-Verwaltung, ... es ist eben ein sehr
zustandsbehaftetes Konstrukt = was man bei Threading so stark wie
möglich vermeiden sollte - Scope Probleme löst man nicht in dem man
einfach globale Zustandsobjekte einbaut - selbst nicht als mögliche
Lösung nennen
alleine das du Singleton im Zusammenhang mit Threads geschrieben hast
lässt mich ein wenig an deiner Erfahrung zweifeln, dann noch der
"dangling-pointer" hinterher - wirkt (sicherlich ungewollt) bastlerisch
>Die wir gar nicht kennen ...!!!
da geben ich dir recht - soll er mal kommen
Bert3 schrieb:>>Das Problem liegt offenbar vor!>> Wo schreibt er das? er hat nur ein Problem mit einem trivial-cast - den> ich vermeiden würden>>>>das noch mehr Probleme macht>>Wo? Welche?>> wenn du n Threads mit m Daten hast - bekommst du entweder> n Singletons oder ein Singleton das n verwalten kann> => Locking, Daten-Reset-Verwaltung,
Das hat man eh, wenn es shared data ist!!!
... es ist eben ein sehr
> zustandsbehaftetes Konstrukt = was man bei Threading so stark wie> möglich vermeiden sollte - Scope Probleme löst man nicht in dem man> einfach globale Zustandsobjekte einbaut - selbst nicht als mögliche> Lösung nennen
aber auch nicht, indem man es ignoriert (s.a. stabiler Code gegen
Refactorierngsauswirkungen, Exception-Safety, in Deinem Vorschlag nicht
gegeben)
> alleine das du Singleton im Zusammenhang mit Threads geschrieben hast> lässt mich ein wenig an deiner Erfahrung zweifeln, dann noch der> "dangling-pointer" hinterher - wirkt (sicherlich ungewollt) bastlerisch
Wenn einem die fachlichen Argumente fehlen ...
Nun, das würde ich genauso zurück geben.
>> wenn du n Threads mit m Daten hast - bekommst du entweder>> n Singletons oder ein Singleton das n verwalten kann>> => Locking, Daten-Reset-Verwaltung,>Das hat man eh, wenn es shared data ist!!!
klar - aber diese data races haben trotzdem nichts mit der Lifetime zu
tun
>> zustandsbehaftetes Konstrukt = was man bei Threading so stark wie>> möglich vermeiden sollte - Scope Probleme löst man nicht in dem man>> einfach globale Zustandsobjekte einbaut - selbst nicht als mögliche>> Lösung nennen>aber auch nicht, indem man es ignoriert (s.a. stabiler Code gegen>Refactorierngsauswirkungen, Exception-Safety, in Deinem Vorschlag nicht>gegeben)
darauf bin ich doch gar nicht eingegangen - und dein Singleton hilft
auch nur bei Teilproblemen - aber ist eben ein globales Zustandsobjekt -
ich kann mir einfach keine Situation vorstellen wo ein Singleton eine
höhere Sicherheit verursacht und auch der Einsatz wird von den meisten
Firmen für die ich arbeite massiv eingeschränkt(oder ich argumentiere
dagegen) - weil leicht nutzbar eben nicht clean und stabil bedeutet
in alle diese Nachteile bin ich schon in dem einen oder anderen Projekt
gelaufen:
https://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)#Nachteile
mein Lieblingsthema damit: (performante) Absicherung, Skalier- und
Testbarkeit - bei den Themen ist ein Singleton immer ganz schnell das
schlechteste Pattern
>Wenn einem die fachlichen Argumente fehlen>Nun, das würde ich genauso zurück geben.
deine Punkte stabiler Code gegen,Refactorierngsauswirkungen,
Exception-Safety ignoriere ich nicht - nur wie ein Singleton da
besonders gut hilft (ohne schlechte Einflüsse ins Design zu bringen)
sehe ich nicht - und Singleton kam von dir
aus dem Wikipedia-Eintrag dazu - und weil er so schön meine Gedanke in
Worte fasst:
>Wegen der vielen Nachteile wird das Singleton-Muster (und auch das Idiom >Double-checked Locking) mitunter schon als Anti-Pattern bewertet. Für >Fälle, in
denen tatsächlich technisch ein passender Bereich für ein >Singleton existiert,
können Singletons aber sinnvoll sein – insbesondere >wenn sie sich auf andere
„einmalige Strukturen“ wie zum Beispiel eine >Abstract Factory beziehen. Trotzdem:
Das korrekte Design von Singletons >ist schwierig – in der Regel schwieriger als
Designs ohne Singletons.
IngC++ schrieb:> Hallo Community,>> ich hänge aktuell an einem kleinen Cast Problem. Vielleicht kann mir da> ein C++ Spezialist mal kurz helfen:>> void test()> {> void* x = NULL;>> vector<MyClass*> myClassList;> myClassList.push_back(new MyClass());>> vector<void*> myList;> myList.push_back(&myClassList);>> x = &myList;>> vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);>> vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>> *>(cast1[0]);>>> cout << cast2.size();>>> }>> Für cast2 kommt komischerweise 0 heraus obwohl ein Element drin sein> müsste. Habe ich irgendwo einen Leichtsinsfehler beim casten gemacht?
Auch wenn es mit widerstrebt, habe ich Deinen Code mal kompilier- und
lauffähig gemacht ...
Bert3 schrieb:> aus dem Wikipedia-Eintrag dazu - und weil er so schön meine Gedanke in> Worte fasst:>>>Wegen der vielen Nachteile wird das Singleton-Muster (und auch das Idiom>>Double-checked Locking) mitunter schon als Anti-Pattern bewertet. Für >Fälle,
Wer redet über double-checked locking? In C++11 ist das nicht nötig!
Genau wie dieses ganze Gekröse hier. Wer verwendet heute noch einen
Compiler der nur C++98 kann? Schwer vorstellbar. Alle diese Probleme
sind in std::thread / std::async gelöst, wenn es denn so low-level sein
soll.
Wilhelm M. schrieb:> Auch wenn es mit widerstrebt, habe ich Deinen Code mal kompilier- und> lauffähig gemacht ...
Etwas spät. Laufender Code wurde schon am Anfang gepostet^^
Wilhelm M. schrieb:> // cast1[0] : void* , ist aber polymorph: MyClass*> MyClass* cast2 = reinterpret_cast<MyClass*>(cast1[0]);
das ist nicht richtig. cast1[0] ist immer noch vector<MyClass*>
nicht"Gast" schrieb:> Wilhelm M. schrieb:>> Auch wenn es mit widerstrebt, habe ich Deinen Code mal kompilier- und>> lauffähig gemacht ...>> Etwas spät. Laufender Code wurde schon am Anfang gepostet^^
Ja, stimmt, sorry, hatte ich ganz überblättert.
>> Wilhelm M. schrieb:>> // cast1[0] : void* , ist aber polymorph: MyClass*>> MyClass* cast2 = reinterpret_cast<MyClass*>(cast1[0]);>> das ist nicht richtig. cast1[0] ist immer noch vector<MyClass*>
Auch da hast Du recht! Nochmal sorry für die Verwirrung.
>Wer verwendet heute noch einen>Compiler der nur C++98 kann? Schwer vorstellbar.
Targets von meinen Kunden sind z.B. VXWorks und QNX mit gcc 4.1.2
oder ältere EDLKs für embedded mit gcc 4.0.x oder ältere Redhats
richtig schlimm ist immer der Wechsel zwischen den verschiedenen Kunden
die unterschiedliche Standards vorgeben, teilweise wandel ich täglich
zwischen C++98 bis C++14, mit gcc, clang und VStudio - und
Exotenkompiler für Solaris, oder auch mal mit Boost, gar kein Boost usw.
- sehr schön
Bert3 schrieb:> Ich denke er meint wohl eher C++03
Mmmh, dann würde ich ihm empfehlen sich entsprechende RAII-Wrapper ala
std::thread, ... selbst zu schreiben. Und ein Ressourcenmgmt via
selbstgebaute SmartPtr, sofern er eben nicht Boost, poco, o.ä. verwenden
kann/will.
>Mmmh, dann würde ich ihm empfehlen sich entsprechende RAII-Wrapper ala>std::thread, ... selbst zu schreiben.
bietet sich an
>Und ein Ressourcenmgmt via>selbstgebaute SmartPtr, sofern er eben nicht Boost, poco, o.ä. verwenden>kann/will.
wenn er angstbefreit ist kann er ja auto_ptr verwenden :)
Bert3 schrieb:>>Mmmh, dann würde ich ihm empfehlen sich entsprechende RAII-Wrapper ala>>std::thread, ... selbst zu schreiben.>> bietet sich an>>>Und ein Ressourcenmgmt via>>selbstgebaute SmartPtr, sofern er eben nicht Boost, poco, o.ä. verwenden>>kann/will.>> wenn er angstbefreit ist kann er ja auto_ptr verwenden :)
Naja, dann braucht er später auch nicht auf C++11 zu migrieren ... ;-))
für jede WinCE Entwicklung ist auch mit VS2008 und C++03 das Ende
erreicht mehr geht nicht - und es gibt sau viele die noch mit WinCE
Geräten arbeiten/anbieten/entwickeln
Bert3 schrieb:> für jede WinCE Entwicklung ist auch mit VS2008 und C++03 das Ende> erreicht mehr geht nicht - und es gibt sau viele die noch mit WinCE> Geräten arbeiten/anbieten/entwickeln
Herzliches Beileid!
>Herzliches Beileid!
bin nicht zu stark betroffen :)
musste nur mal eine komplette C+11 Entwicklung (mit shared/unique-ptr,
lambdas usw., ca. 200k LOC) auf WinCE backporten - ein riesen Spass
Bert3 schrieb:>>Herzliches Beileid!>> bin nicht zu stark betroffen :)>> musste nur mal eine komplette C+11 Entwicklung (mit shared/unique-ptr,> lambdas usw., ca. 200k LOC) auf WinCE backporten - ein riesen Spass
Und ich freue mich seit geraumer Zeit über Concepts / Constraints, und
mag gar nicht mehr ohne, und warte ungeduldig, dass auch modules
(zumindest als lite version wie im clang) im gcc Einzug halten ;-)
und conditions, usw. alles was <thread> so hergibt - Grund: man hatte
anders geplant, wollte die "alte" Platform nicht mehr supporten, dann
kam ein Kunde, mit ordentlich Geld - los gehts!
Bert3 schrieb:> und conditions, usw. alles was <thread> so hergibt - Grund: man hatte> anders geplant, wollte die "alte" Platform nicht mehr supporten, dann> kam ein Kunde, mit ordentlich Geld - los gehts!
Naja, die Bibliothekssachen kann man zur Not noch selbst bauen. Aber
Concepts und auch z.B. Variadic Templates odet constexpr sind eben neue
Sprachfeatures.