Forum: PC-Programmierung C++ reinterpret vector<void*>


von IngC++ (Gast)


Lesenswert?

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++

von nicht"Gast" (Gast)


Lesenswert?

Was zum Henker....

von Peter II (Gast)


Lesenswert?

bin mir jetzt nicht ganz sicher, aber die vectoren werden hier noch mal 
kopiert.
1
vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>
2
*>(cast1[0]);

sicher das du das willst?

mit einem Typedef könnte man das auch lesbarer schreiben.

von IngC++ (Gast)


Lesenswert?

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...

von Mikro 7. (mikro77)


Lesenswert?

1
#include <iostream>
2
#include <vector>
3
4
struct MyClass { } ;
5
6
using namespace std ;
7
8
void test()
9
{
10
   void* x = NULL;
11
12
   vector<MyClass*> myClassList;
13
   myClassList.push_back(new MyClass());
14
15
   vector<void*> myList;
16
   myList.push_back(&myClassList);
17
18
   x = &myList;
19
20
   vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);
21
22
   vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*> *>(cast1[0]);
23
24
  cout << cast2.size();
25
}
1
$ g++ -Wall -c test.cc 
2
test.cc: In function ‘void test()’:
3
test.cc:22:74: error: conversion from ‘std::vector<MyClass*>*’ to non-scalar type ‘std::vector<MyClass*>’ requested
4
    vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*> *>(cast1[0]);

: Bearbeitet durch User
von nicht"Gast" (Gast)


Lesenswert?

damig, zu spät :)

von nicht"Gast" (Gast)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

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

von IngC++ (Gast)


Lesenswert?

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 :-)

von IngC++ (Gast)


Lesenswert?

IngC++ schrieb:
> 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]);

von Mikro 7. (mikro77)


Lesenswert?

1
#include <iostream>
2
#include <vector>
3
4
struct MyClass { } ;
5
6
using namespace std ;
7
8
int main()
9
{
10
   void* x = NULL;
11
12
   vector<MyClass*> myClassList;
13
   myClassList.push_back(new MyClass());
14
15
   vector<void*> myList;
16
   myList.push_back(&myClassList);
17
18
   x = &myList;
19
20
   vector<void*> cast1 = *reinterpret_cast<vector<void*> *>(x);
21
22
   vector<MyClass*> cast2 = *reinterpret_cast<vector<MyClass*> *>(cast1[0]);
23
24
   cout << cast2.size();
25
26
   return 0 ;
27
}
1
$ g++ -Wall -o test test.cc 
2
$ ./test
3
1

von IngC++ (Gast)


Lesenswert?

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!

von Dr. Sommer (Gast)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

Nebenbei bemerkt gibt es nullptr erst ab C++ 11. Ich nutze C++ 98, von 
daher bin ich etwas eingeschränkter.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ...

von lalala (Gast)


Lesenswert?

Wilhelm M. schrieb:
> nicht den richtigen DT? Abgesehen davon, dass das ganze abenteuerlich
> ist ...

Vermutlich soll das ganze spaeter Polymorphismus emulieren...

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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?

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

Beitrag #5026933 wurde vom Autor gelöscht.
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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.

von Sebastian V. (sebi_s)


Lesenswert?

Ja habs auch gerade gesehen...

von Wilhelm M. (wimalopaan)


Lesenswert?

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...

: Bearbeitet durch User
von IngC++ (Gast)


Lesenswert?

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 :-)

von Wilhelm M. (wimalopaan)


Lesenswert?

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

von IngC++ (Gast)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

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.

von IngC++ (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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).

von Dr. Sommer (Gast)


Lesenswert?

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!

von Bert3 (Gast)


Lesenswert?

@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

von Wilhelm M. (wimalopaan)


Lesenswert?

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!

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

Bert3 schrieb:

>
> DatenKapselKlasse daten;
> CreateThread((void*)&daten)

Wenn das ne lokale Variable ist, ist es schon falsch!!!

von Wilhelm M. (wimalopaan)


Lesenswert?

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).

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Bert3 (Gast)


Lesenswert?

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

von Bert3 (Gast)


Lesenswert?

>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

von Wilhelm M. (wimalopaan)


Lesenswert?

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!

von Bert3 (Gast)


Lesenswert?

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

von Bert3 (Gast)


Lesenswert?

>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

von Bert3 (Gast)


Lesenswert?

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

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ...

von Bert3 (Gast)


Lesenswert?

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)

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ...

von Bert3 (Gast)


Lesenswert?

>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

von Wilhelm M. (wimalopaan)


Lesenswert?

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!

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ...!!!

von Bert3 (Gast)


Lesenswert?

>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

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Bert3 (Gast)


Lesenswert?

>> 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

von Bert3 (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ...
1
    void* x = nullptr; 
2
    
3
    vector<MyClass*> myClassList;
4
    myClassList.push_back(new MyClass()); // leak
5
    
6
    vector<void*> myList;
7
    myList.push_back(&myClassList);
8
    
9
    x = &myList; // x : vector<void*>*
10
    
11
    vector<void*> cast1 = *reinterpret_cast<vector<void*>*>(x); // cast1 == myList
12
    
13
//    vector<MyClass*> cast2 = reinterpret_cast<vector<MyClass*>*>(cast1[0]); // Fehler 
14
    
15
    // cast1[0] : void* , ist aber polymorph: MyClass*
16
    MyClass* cast2 = reinterpret_cast<MyClass*>(cast1[0]); 
17
    
18
    cast2->f();
19
    
20
//    cout << cast2.size(); // falsch
21
    std::cout << cast1.size() << '\n';

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von nicht"Gast" (Gast)


Lesenswert?

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*>

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Bert3 (Gast)


Lesenswert?

>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

von Bert3 (Gast)


Lesenswert?

Ich denke er meint wohl eher C++03

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Bert3 (Gast)


Lesenswert?

>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 :)

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ... ;-))

von Bert3 (Gast)


Lesenswert?

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

von Wilhelm M. (wimalopaan)


Lesenswert?

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!

von Bert3 (Gast)


Lesenswert?

>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

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ;-)

von Bert3 (Gast)


Lesenswert?

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!

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.