Doppeldeutigkeit nach mehrfachvererbung
-
-
gamer8o4 schrieb:
nein ich kann es nicht ohne mehrfachvererbung lösen, das geht echt nicht, weil die erste klasse das singleton design pattern threadsafe implementiert und die zweite klasse einfach eine andere klasse in meiner bibliothek ist, welche ich auch als "nicht-singleton" verwenden will.
Doch, ich glaube schon. Muss man wirklich, um eine bestimmte Theadsicherheit zu haben, von einer Threradsicherheitsklasse erben? Muss man von Singletons erben? Da liegt der Wurm.
Heute mal kannste mit
cout << d1.c1::i;weitermachen. Aber das macht mich nicht glücklich.
-
Sone & Tobiking2 schrieb:
Diamond-Problem
Echt? Nö, eigentlich nicht.
-
gamer8o4 schrieb:
nein ich kann es nicht ohne mehrfachvererbung lösen, das geht echt nicht, weil die erste klasse das singleton design pattern threadsafe implementiert und die zweite klasse einfach eine andere klasse in meiner bibliothek ist, welche ich auch als "nicht-singleton" verwenden will.
Wofür genau brauchst du das Singleton da? Sowas interessiert mich immer, weil ich in über 10 Jahren noch keinen einzigen sinnvollen Anwendungsfall des Singleton Pattern gesehen hab. Vielleicht hab ich ja Glück und du bist tatsächlich der erste, der einen gefunden hat...

-
das diamond ding lese ich mir morgen mal durch und melde mich dann wieder (jetzt ist zu spät)
den singleton brauche ich total oft, die sinnvollste anwendungsmöglichkeit ist bei mir glaube ich ein small-object-allocator, von dem es nicht zwei geben darf, weil es sonst zu speicherfehlern kommt.
als zweites hat z.b mein filesystem einige bestandteile die singletons sind.ich glaube du brauchst singletons nie, weil du einfach sagst okay, ich nehme einfach das was in die singletonklasse sollte und nehme anstatt der klasse einfach einen namespace und packe da die ganzen sachen rein?
ich mag singletons aber irwie lieber, weil ich dann mehr kontrolle habe wann was erstellt und gelöscht wird und ich kann im destructor alles aufräumen
-
gamer8o4 schrieb:
ich glaube du brauchst singletons nie, weil du einfach sagst okay, ich nehme einfach das was in die singletonklasse sollte und nehme anstatt der klasse einfach einen namespace und packe da die ganzen sachen rein?
Ne, wir tun das ganze in eine Klasse, verspüren aber nicht den Drang, sie gleich zu einem Singleton (und damit zu einer globalen Variable) zu machen

Eine Klasse, die nur ein einziges Mal instanziiert wird, rechtfertigt alleine noch kein Singleton! Das wird sehr oft falsch verstanden. Auch scheint mir die Problematik, man könne aus Versehen mehrere Instanzen anlegen, in sehr vielen Situationen inexistent. In gutem Design hat eine Klasse meist einen genau definierten Platz, relativ wenige Objekte sind "einfach so da". Natürlich gibts immer Ausnahmen, sowas wie Logging oder Speicherverwaltung könnte eventuell dazu gehören.
gamer8o4 schrieb:
ich mag singletons aber irwie lieber, weil ich dann mehr kontrolle habe wann was erstellt und gelöscht wird und ich kann im destructor alles aufräumen
Du hast viel weniger Kontrolle mit Singletons. Erstens, da globaler Zugriff möglich ist, kannst du diesen nicht kontrollieren oder limitieren. Man kann von überall her auf die Instanz zugreifen. Dadurch entstehende Seiteneffekte können mühsame Bugs mit sich bringen. Die Modularität geht verloren, Design-Abhängigkeiten innerhalb des Programms nehmen zu, was Wartung wiederum erschwert. Zweitens, du hast keine bzw. sehr eingeschränkte Kontrolle über die Lebenszeit der Instanzen, weil du der statischen Speicherklasse unterworfen bist. Das ist besonders mühsam, wenn du Abhängigkeiten zwischen mehreren Singletons hast. Drittens, du hast keine Threadsicherheit, oder musst dauernd teuer locken und synchrone Zugriffe sicherstellen.
Alles Probleme, die du bei Klassen mit lokalem Zuständigkeitsbereich nicht hast.
-
gamer8o4 schrieb:
den singleton brauche ich total oft
Gut gemeinter Rat: Damit solltest du schnellstmöglich aufhören.
gamer8o4 schrieb:
[...] die sinnvollste anwendungsmöglichkeit ist bei mir glaube ich ein small-object-allocator, von dem es nicht zwei geben darf, weil es sonst zu speicherfehlern kommt.
Wieso kommt es sonst zu Speicherfehlern?
gamer8o4 schrieb:
ich mag singletons aber irwie lieber, weil ich dann mehr kontrolle habe wann was erstellt und gelöscht wird und ich kann im destructor alles aufräumen

Tatsächlich? Wie genau kontrollierst du denn das bei einem Singleton? Und wieso kannst du nur bei einem Singleton "im Destruktor aufräumen"!?
-
dot schrieb:
gamer8o4 schrieb:
[...] die sinnvollste anwendungsmöglichkeit ist bei mir glaube ich ein small-object-allocator, von dem es nicht zwei geben darf, weil es sonst zu speicherfehlern kommt.
Wieso kommt es sonst zu Speicherfehlern?
Ich fange noch früher an: Warum small-object-allocator? Das klingt mir danach, dass da viel zu schnell new verwendet wird, wo im Zweifelsfall ein std::vector viele Instanzen gleichzeitig verwalten könnte. Und der SOA ist nur zur Linderung der Symptome da.
warum sollte ein Logger ein Singleton sein? Selbst wenn es nur einen einzigen Logger geen dürfte, würden mir da spontan mindestens 3 einfachere Designs einfallen, eines davon:
void log(std::string const& message, LogType type);Warum überhaupt ein Logger? Weil das coole Kids heute so machen?
Warum
int i : 11;anstatt
int i;?
-
Sone schrieb:
Das ist das klassische Beispiel des Diamond-Problems.
Wie volkard schon sagte, der Diamond of Death ists nicht. Das wäre er wenn die beiden Oberklassen nochmal von ein- und derselben Basisklasse erben würden und die angepeilte Variable in der obersten Basisklasse definiert wäre.
Mh, was mich mal interessieren würde. Wie erbt man von einem Singleton sinnvoll?
Wenn wir mal hiervon ausgehen.class SingletonBase { SingletonBase(){} SingletonBase(SingletonBase const&); // = delete SingletonBase& operator=(SingletonBase); // = delete public: static SingletonBase& getInstance() { static SingletonBase s; return s; } };Dann ist ganz schnell klar, dass static + Inheritance nicht harmonieren, sprich vererben geht nicht.
Auf diese folgende Weise schafft man zwar eine Vererbungshierarchy, aber es hat eigentlich nur Nachteile.
class SingletonBase { protected: SingletonBase(){} private: SingletonBase(SingletonBase const&); // = delete SingletonBase& operator=(SingletonBase); // = delete public: static SingletonBase& getInstance() { static SingletonBase * s = cond ? new SingletonBase : new SingletonDerive; // mal abgesehen von der manuellen Speicherinkontinenz return s; } virtual ~SingletonBase(){} }; class SingletonDerive : public SingletonBase { };Wie macht man das in der Praxis?
(Oben die 2 Beispiel sind ohne viel Denken jetzt von mir kurz runtergeschrieben)
-
volkard schrieb:
Sone & Tobiking2 schrieb:
Diamond-Problem
Echt? Nö, eigentlich nicht.
Skym0sh0 schrieb:
Wie volkard schon sagte, der Diamond of Death ists nicht. Das wäre er wenn die beiden Oberklassen nochmal von ein- und derselben Basisklasse erben würden und die angepeilte Variable in der obersten Basisklasse definiert wäre.
Was versteht Ihr denn anderes als das Diamond-Problem unter der Aussage vom TE?
gamer804 schrieb:
Im original code habe ich zwei klassen die beide die klasse CDefaultThreadingModel erben.
nun will ich eine dritte klasse erstellen, welche sich von den beiden ersten klassen ableitet, aber habe natürlich das problem, dass die member von CDefaultThreadingModel doppelt existieren
-
Das stimmt schon so.
Aber das gegebene Beispiel vom TE spiegelt nicht das Diamond Problem wieder.
-
Mh, was mich mal interessieren würde. Wie erbt man von einem Singleton sinnvoll?
Wenn wir mal hiervon ausgehen.also so sieht mein grundgerüst aus:
(eine abgewandelte version von dem singleton von andrei alexandrescu)// CSingleton // -> this class is a very variable implementation of the Singleton design pattern descriped by the GoF // "Ensure a class only has one instance, and provide a global point of access to it." template< class T, template<class> class TLifetime = DELTA_CORE_SINGLETON_LIFETIME_DEFAULT, template<class> class TAlloc = DELTA_CORE_ALLOCATOR_DEFAULT, template<class,class> class TThreadingModel = DELTA_CORE_THREAD_MODEL_CLASSLEVEL, class TMutex = DELTA_CORE_THREAD_MUTEX_DEFAULT > class CSingleton{ public: typedef T obj_type; // type of the singleton object static obj_type& getInstance(); private: // Helpers static void createSingleton(); static void destroySingleton(); // Protection CSingleton(); CSingleton(const CSingleton&); CSingleton& operator=(const CSingleton&); ~CSingleton(); // Data typedef typename TThreadingModel<T*,TMutex>::volatile_type ptr_instance_type; static ptr_instance_type m_instance; static bool m_destroyed; };class c : public CSingleton<c>{ };damit solltest du schnellstmöglich aufhören
Ich glaube ich sollte echt mal drauf achten, dass ich singleton viel seltener benutze. ich glaube ich sollte anders denken und versuchen umwege zu nehmen.
...ach ich hab ja noch zeit das alles nen bisschen zu üben (bin ja erst 16)Wieso kommt es sonst zu Speicherfehlern?
die klasse ist noch nicht ganz fertig, aber jetzt wo du es sagst... warum eigentlich
ich glaube ich hab da irgentwo einen anderen fehler, ich gucke nochmal nachher nach.Das ist das klassische Beispiel des Diamond-Problems.
scheint genau das zu sein was ich brauche, ich versuche dann mal das in meinen code zu implementieren.
ich mag singletons aber irwie lieber, weil ich dann mehr kontrolle habe wann was erstellt und gelöscht wird und ich kann im destructor alles aufräumen
Tatsächlich? Wie genau kontrollierst du denn das bei einem Singleton? Und wieso kannst du nur bei einem Singleton "im Destruktor aufräumen"!?
nein kann ich nicht nur bei singletons, das war auf den umweg bezogen alles als globale funktionen und globale variablen zu schreiben und dann hätte ich für die globalen variablen keinen destructor.
-
CSchmeiss Cdoch Cdie Tganzen TPraefixe Tweg. CPfui.
-
CSchmeiss Cdoch Cdie Tganzen TPraefixe Tweg. CPfui.
hab ich mir so angewöhnt, dann weiß man immer direkt was eingabe und was membervariablen sind, man erkennt direkt klassen und datenstrukturen und templateparameter und und und...
ich finde es angenehmer einen solchen code im nachhinein zu ändern also ne
ich lasse das nicht...
-
gamer8o4 schrieb:
hab ich mir so angewöhnt
UN ist eine der schlimmsten Angewohnheiten von C++-Programmierern.
Siehe hier.
-
UN ist eine der schlimmsten Angewohnheiten von C++-Programmierern.ungarische notation heißt soweit ich weiß, dass man bei allen variablen den typ abgekürzt davor schreibt.
Ich schreibe ja nur C T m_ p_ das war es und ich finde das hat wenig mit UN zu tun...
mir ist klar, dass es unnötig solche sachen wie das folgende zu schreiben, aber das macht ja auch niemandconst unsigned long long* m_kull_ptr_MyVar = nullptr;
-
gamer8o4 schrieb:
Ich schreibe ja nur C T m_ p_ das war es und ich finde das hat wenig mit UN zu tun...
Lies mal meinen Link ausführlich.
Falls das nicht reicht, kein Problem. Ich habe auch einen separaten Post nur den C-Präfixen gewidmet

-
gamer8o4 schrieb:
damit solltest du schnellstmöglich aufhören
Ich glaube ich sollte echt mal drauf achten, dass ich singleton viel seltener benutze. ich glaube ich sollte anders denken und versuchen umwege zu nehmen.
...ach ich hab ja noch zeit das alles nen bisschen zu üben (bin ja erst 16)Ähm. Nicht das Vermeiden der Singletons ist der Umweg, sondern das Benutzen. Das klingt gerade, als würde man Dir eine Säge wegnehmen und Du würdest jammern, daß man mit dem Schraubenzieher noch schlechter Blumen gießen kann.
gamer8o4 schrieb:
nein kann ich nicht nur bei singletons, das war auf den umweg bezogen alles als globale funktionen und globale variablen zu schreiben und dann hätte ich für die globalen variablen keinen destructor.
Da ist doch schon das Problem. Du verwendest überall globale Variablen. Nochmal: Da ist das Problem. Daß du die globalen Variablen dann als Singletons tarnst, ist keine wirklich tragfähige Lösung.
-
...
-
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Regel Nr.1 für die Anwendung von Singletons: Niemals von Singletons ableiten !!!
----------------------------------------------------------------------------------------------------------------------------------------------------------------Egal was man auch immer für eine Klasse, für was auch immer für einen Anwendungsfall hat.
Die Bedingung nur eine Instanz davon zu erlauben ist kontextabhängig und hat in allen Fällen nichts mit der Klasse selbst zu tun.class c { // aus bequemlichkeit innerhalb der klasse realisiert c* instance() { return singleton<c>::instance(); } }Das Singleton Interface kann auch total außerhalb der Klasse sein.
// freie funktion c* single_instance() { return singleton<c>::instance(); }Merke: Siehst du eine Klasse, die von einem Singleton erbt, hat es ein Anfänger programmiert.