C++ reinterpret vector<void*>

Gast #5026698
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++
Gast #5026724
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.
Gast #5026749
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...
#5026751
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]);
Gast #5026757
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
Gast #5026759
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 :-)
Gast #5026760
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]);
#5026763
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
Gast #5026783
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.
Gast #5026789
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.
Gast #5026804
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.
#5026886
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.
#5026903
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 ...
Beitrag #5026933 wurde von einem Moderator gelöscht.
(Firma: Torrox.de) #5026939
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.
Gast #5027011
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 :-)
Gast #5027023
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.
Gast #5027024
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.
#5027025
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.
Gast #5027027
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.
Gast #5027028
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.
#5027040
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.
#5027052
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).
Gast #5027284
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!
Gast #5027293
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
#5027372
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!
#5027382
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).
#5027384
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.
Gast #5027393
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
Gast #5027400
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
#5027404
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 ...
Gast #5027405
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)
#5027408
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 ...
Gast #5027411
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
#5027416
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 ...!!!
Gast #5027422
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
#5027541
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.
Gast #5027557
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
Gast #5027560
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.
#5027584
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';
#5027592
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.
#5027600
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.
Gast #5027619
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
Gast #5027631
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 :)
#5027632
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 ... ;-))
#5027659
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 ;-)
#5027664
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren