C++ Templates und virtuelle Methoden

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

Hallo Freunde der Sonne!

Ich habe eine Frage zum Thema C++/Templates/Vererbung. Ich ahne, dass ich mich später dafür schämen werde, sowas gebaut und dann noch gefragt zu haben, aber es lässt mir keine Ruhe:

Nun: Ich lese immer, dass "virtual" methods und Templates nicht zusammenpassen, da das eine zur Laufzeit stattfindet und das andere zur Compile-Time.
Jetzt habe ich folgendes Scenario (mal vereinfacht/etwas synthetisiert):

Code: Alles auswählen


//definiere Template, welches als Basis-Klasse/Basis-Template für andere Templates gilt
template <typename T> class TBaseCollection  {
public:
    [...]
    virtual int               getCount	() const = 0;
    virtual const T&     operator[]	(int) const = 0;
    void            doConvinientAndCommonStuff() {
                        [do something here which is common for all collections]
                       int a = getCount();  // call virtual method defined here (to be implemented in derived template class)
                       [...]
                     }
};

// leite von Basistemplate ab und implementiere abstrakte/virtuelle Methoden
template <typename T> class TArray : public TBaseCollection<T> {
public:
	int		getCount () const {
		return (10); // silly example, but does the job
	}
	const T&	operator [](int Index) const {
		return Items[Index]; // just return the simple item here without having boilerplate code here
	}
private:
	T		m_Items[10]; // silly example with static content
};
Ich definiere quasi im Basistemplate Methoden , die in der Implementierung des Basistemplates gecallt werden, aber erst im der ableitenden Template implementiert werden.
Wie gesagt lese ich immer (auch von Stroustrup persönlich), das virtuelle Methoden und Templates in Kombi sinnlos sind. Ich erkenne hier aber einen Sinn und es funktioniert auch.

Mein Code kompiliert mit MSVC und dem GCC gut und beides läuft geschmiert - wie es sein soll.

Nun meine Frage: Funktioniert es nur zufällig, weil der Kompiler dem Ganzen doch irgendeinen Sinn gibt, der ursprünglich nicht definiert ist?

Wenn mein Ansatz falsch ist, wie könnte ich es richtig machen?

Klar könnte ich "int getCount() const" in eine abstrakte Basisklasse (kein Template) ziehen, von der dann das Basis-Template TBaseCollection selbst ableitet. Aber was mache ich dann mit "const T& operator[] (int) const = 0;" , was ja typbezogen sein muss und daher Teil des Templates sein sollte.

Geht da was mit meinem Verständnis von "virtuelle Methoden" (Benutzung von schlüsselwortes virtual) und "abstrakten Methoden" (nicht impementiert: "void blah() = 0" ) schief? Wo ist mein Denk-/Designfehler? Wie geht es "richtiger"? *Confused*
Zuletzt geändert von Top-OR am 05.08.2016, 10:56, insgesamt 1-mal geändert.
--
Verallgemeinerungen sind IMMER falsch.
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: C++ Templates und virtuelle Methoden

Beitrag von DerAlbi »

Ich finde das gut so, wie es ist. Ich glaube, dass du da irgendwelchen Leuten aufgelaufen bist, die meinen, es gäbe strikte Designdogmata die man nicht tun dürfte, obwohl man sie offensichtlich implementieren kann. Warum ein Stroustrup so etwas sagt, weiß ich nicht.. vermutlich ist kein Anwendungsszenario dafür eingefallen. Ich erkenne bei dir auch den Sinn dahinter und ich hab das auch schon so gemacht. Natürlich kann man von Templates ganz normal ableiten. Man kann auch von NormalKlasse->TemplateKlasse oder von TemplateKlasse->Normalklasse ableiten. Je nach Anwendung.
Mach noch ein Goto in den Quelltext, vorzugsweise in das innere von zwei verschachtelten Schleifen mit Sprungziel nach außen :-) Dann kommen die Schreikinder alle aus ihren Löchern und du weißt auf wen du nicht hören musst :-)
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

Moin Albi!

Danke für deine Antwort - so habe ich zumindest mal das Gefühl, dass es ein total abwegiger Bullshit ist, den ich da gebaut habe - zumal er ja zumindest sinnvoll erscheint.

Ich hoffe auch noch, dass diese Aussage zu "C++ templates virtual methods" im Netz (einfach mal googlen -> StackOverflow & Co) in der Summe von Leuten kommen, die die Handhabung Ihrer Programmiersprache mal wieder zu religiös nehmen bzw. sich keinen sinnvollen Use Case vorstellen können.

Ich bin drauf gekommen, als ich dieses Video von Bjarne Strouchstrup himself angesehen habe:
[youtube]86xWVb4XIyE[/youtube]
Das Vid ist ja eher ne schnelle Tour durch die Sprache mit eine paar Kommentaren vom "Erfinder" der Sprache selbst. Aber an einer Stelle (weiss die Minute nicht mehr) sagt er eben auch sowas in der Richtung, dass das Mischen von Templates und virtuellen Methoden nicht so toll wäre (im Sinne von sinnlos) - so habe ich das zumindest verstanden. Und wenn der Papa von C++ das so sagt, nehme ich das schon ernster, als wenn ichs nur in ein paar Foren von ein paar Sprachfundamentalisten aufgeschnappt hätte... Und forsche mal nach. ;-)

Andererseits sind die Kombinationsmöglichkeiten bestimmter Konstrukte so vielfältig, dass auch der "Erfinder" nicht alle Use Cases vorhersehen kann und Dinge vielleicht manchmal doch sinnvoll sind.

Naja ... Verallgemeinerungen sind eben immer falsch ... *Dooooh*

Also .. danke erstmal soweit.
Die ursprüngliche Befürchtung, etwas gebaut zu haben, was nur durch "undefinierte Kompilereffekte zufällig funktioniert" ist erstmal entschärft.

Vielleicht meldet sich noch der eine oder andere mit Senf dazu (würde ich begrüßen)...
--
Verallgemeinerungen sind IMMER falsch.
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: C++ Templates und virtuelle Methoden

Beitrag von DerAlbi »

Also ich habe mir das Video gerade angeschaut :-) Cool.
Es wurde aber com Chef persönlich erstmal keine Aussage dahingehend getroffen, was ok ist und was nicht. Er sagt sogar explizit (allerdings politisch korrekt), dass die Leute, die sowas pauschalisieren Deppen ohnesgleichen sind.
In der Q&A-Sektion gibt es eine Frage zu Konstrukten wie deinen, weil sie für Anfänger (oder einsteiger in große Projekte) eine Hürde darstellen - was auch stimmt. Aber das bedeutet nicht, dass derartige Konstrukte schlecht sind. Wenn sie nötig sind, sind die halt nötig.

Was allerdings gesagt wurde ist, dass Vererbung natürlich durch die zusätzliche Indirektion das Inlining und damit die Performance killt. Gerade Templates schreibt man oft mit dem Hintergrund, dass man typenspezifische (compoiletime-)Optimierungen direkt vom Compiler incl inlining usw. will. Das paart sich halt nicht gut mit Vererbung.
Als Beispiel wird dein überladener []-Operator total vor die Hunde gehen (im Verlgeich mit einem direkten Speicherzugriff / üblichen []-Operator). Aber wenn es dein Inferface so verlangt ist es dennoch eine elegante Lösung. Man muss als Programmierer einfach wissen, welche Tradeoffs man eingeht.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Dein Code ist an sich nicht falsch und sollte funktionieren. Die Frage ist allerdings, was genau du damit erreichen willst. Wofür genau brauchst du den Polymorphismus durch diese TBaseCollection?
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

dot hat geschrieben:Dein Code ist an sich nicht falsch und sollte funktionieren. Die Frage ist allerdings, was genau du damit erreichen willst. Wofür genau brauchst du den Polymorphismus durch diese TBaseCollection?
"Brauchen" tu ich die nicht. Ich finde die Idee charmant, dass alle Collections, seien es Listen, Arrays, Pointer(sind in meinem Universum Arrays, die Ihren Speicher nicht selbst besitzen/verwalten), Hashmaps etc. ein grundlegendes gemeinsames Interface haben und ich z.B. darauf aufbauend die Inhalte einer Hashmap(Values) direkt in einen Array kopieren kann; und das in Standard-Notation:

Code: Alles auswählen

ListenObjekt = ArrayObjekt;
Ich finde, das erhöht die Lesbarkeit (für den Preis, dass es vielleicht langsamer ist) in den höheren Abstraktionsebenen, die das Zeug eben nur noch benutzen. Meine Codebase erreicht langsam einen Umfang/Level, wo ich Lesbarkeit pushen muss und Geschwindigkeit (im aktuellen Use Case) opfern kann.

Ich finde es gut, wenn gewisse Containerklassen eben durch ein Interface standardisierte Zugriffsmethoden haben, die bei allen Typen von Containern zumindest ein gemeinsames Ergebnis liefern (Wenn auch u.U. langsamer).

Außerdem: So kann ich, wenn ich merke, dass ich für eine gewisse Anwendung lieber eine andere Softe von Container brauche, den Container austauschen, ohne die benutzende Implementierung, die den Container befüllt oder leersaugt, zu ändern. Sie operiert dann auf dem kleinsten gemeinsamen Interface der Containerklassen und muss nicht wissen, ob es ein Array, Liste oder ein Pointer ist.

Oder im Beispiel von oben:
Ich will, dass alle Container die selbe Methode "doConvinientAndCommonStuff()" haben, die immer (möglichst) gleich reagiert.
--
Verallgemeinerungen sind IMMER falsch.
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: C++ Templates und virtuelle Methoden

Beitrag von Spiele Programmierer »

Erstmal: Was du gebaut hast scheint mir völlig legitim.

Ich stimme aber Dot zu: Wozu das ganze?
Standardisierter Zugriff ist eine feine Sache, allerdings wirst du mit dem Interface zB. keine Hashmaps ansprechen können, weil du dich mit getCount dem int im operator[] auf Arrays beschränkst. (Besser wäre übrigens size_t, weil du dann zB. auf 64 Bit entsprechend skalierst und sonst Konvertierungswarnungen auftreten, wenn du es zB. mit Pointern, Iteratoren oder std:: Containern verbindest die alle size_t/ptrdiff_t verwenden)

Standardisierten Zugriff kannst du allerdings auch ohne virtual calls haben. Jeder Container hat einfach die selben Zugriffsmethoden. So wie die std:: Container.
Ich finde die Idee charmant, dass alle Collections, seien es Listen, Arrays, Pointer(sind in meinem Universum Arrays, die Ihren Speicher nicht selbst besitzen/verwalten)
Für diesen Zweck würde ich dir eine einfache "array_view" Klasse nahelegen. (Wird in der neusten Reinkarnation auch manchmal span genannt.) Also eine Klasse die einfach zwei Pointer (begin und end) besitzt und die üblichen Container Methoden (operator[], size, empty, begin, end, etc.) sowie slice Methoden definiert. Meine Implementierung hat gerade mal 400 Zeilen, so kompliziert ist das nicht. Damit hast du ein Interface für alle Listen, egal woher sie stammen. std::vector, std::array, Fixed Size C Arrays, etc. kannst du implizit konvertierbar zu dieser Klasse machen. Ich kann dir sagen, dass diese Klasse mir unglaublich viel Zeit und Ärger gespart hat, dadurch dass ich nicht mehr einzeln einen Pointer und die Länge übergeben muss. Außerdem kann man in die Klasse im operator[] ein paar Debug Assert Range Checks reinpacken. Das tut Wunder. Nur Linked Lists kann man damit nicht darstellen: Allerdings die passen in dein "TBaseCollection" Interface eben so wenig und in der Regel lässt man eh besser die Finger von Linked Lists.

Weil dir scheinbar sehr viel an der Meinung von Stroustrup liegt: In den C++ Core Guidelines empfiehlt er diese Klasse und ich habe irgendwo mal ein Video von ihm gesehen, in dem er sich darüber aufgeregt hat das diese einfache Klasse es noch nicht in die STL geschaft hat.
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

Hi Spiele Programmierer.

Oha - viel Stoff. Danke für die Einschätzung. Also...
Spiele Programmierer hat geschrieben:Erstmal: Was du gebaut hast scheint mir völlig legitim.
Genau das interessiert mich auf einem technischen Level...
Spiele Programmierer hat geschrieben:Ich stimme aber Dot zu: Wozu das ganze?
Diese Frage stelle ich mir seit 20 Jahren, seit ich damals unter DOS in Pascal perspektivisch korrekte Software-Polygonrasterizer nachprogrammiert habe. Diese Frage trifft auf alle Betrachtungsebenen meines Hobby-Projektes zu. Ich beantworte sie seit einigen Jahren auch für mich selbst mit:
"Weil ich es kann". (im Sinne von technisch möglich) Es entspannt mich einfach. Sinnlos, aber entspannend - Hobby eben.
Spiele Programmierer hat geschrieben:Standardisierter Zugriff ist eine feine Sache, allerdings wirst du mit dem Interface zB. keine Hashmaps ansprechen können...,

Falsch .. mache ich bereits seit Jahren und es funktioniert ja. Diese Code-Fragment sind ja nur exemplarischer Peusocode.
Spiele Programmierer hat geschrieben: ... weil du dich mit getCount dem int im operator[] auf Arrays beschränkst. (Besser wäre übrigens size_t, weil du dann zB. auf 64 Bit entsprechend skalierst und sonst Konvertierungswarnungen auftreten, wenn du es zB. mit Pointern, Iteratoren oder std:: Containern verbindest die alle size_t/ptrdiff_t verwenden)
Ich glaube, da komme ich erst im nächsten Leben zu.
Spiele Programmierer hat geschrieben:Standardisierten Zugriff kannst du allerdings auch ohne virtual calls haben. Jeder Container hat einfach die selben Zugriffsmethoden. So wie die std:: Container.
Ne, ich glaube, einer von uns beiden versteht den anderen gerade nicht (nicht zynisch gemeint).
Es geht darum, dass die Implementierungen, die auch der Collection arbeiten, nur das Interface (abstrakte Basisklasse unter TCollection, quasi ICollection) kennen und damit operieren. Es geht nicht darum, dass die Methoden "nur gleich heissen", dass ich sie besser verstehe.
Spiele Programmierer hat geschrieben:
Ich finde die Idee charmant, dass alle Collections, seien es Listen, Arrays, Pointer(sind in meinem Universum Arrays, die Ihren Speicher nicht selbst besitzen/verwalten)
Für diesen Zweck würde ich dir eine einfache "array_view" Klasse nahelegen. (Wird in der neusten Reinkarnation auch manchmal span genannt.) Also eine Klasse die einfach zwei Pointer (begin und end) besitzt und die üblichen Container Methoden (operator[], size, empty, begin, end, etc.) sowie slice Methoden definiert. Meine Implementierung hat gerade mal 400 Zeilen, so kompliziert ist das nicht. Damit hast du ein Interface für alle Listen, egal woher sie stammen.
Ja, sowas habe ich auch, heisst eben seit Jahren Pointer (bissel irreführendes naming) bei mir (Verwaltet Beginn und Ende und macht Range Checks, ohne den Speicher zu Ownen und kann von echt vielen fachlichen Klassen als "Zugriffmedium" auf Speicher ausgespuckt werden). Das hat aber Nichts damit zu tun, dass dieser Pointer UND die Collections selbst eben ein gemeinsames Interface implementieren.
Spiele Programmierer hat geschrieben:std::vector, std::array, Fixed Size C Arrays, etc. kannst du implizit konvertierbar zu dieser Klasse machen. Ich kann dir sagen, dass diese Klasse mir unglaublich viel Zeit und Ärger gespart hat, dadurch dass ich nicht mehr einzeln einen Pointer und die Länge übergeben muss. Außerdem kann man in die Klasse im operator[] ein paar Debug Assert Range Checks reinpacken. Das tut Wunder.
Ich habe mir die eigenen Container mal gebaut, um zu lernen, was da eigentlich dahintersteckt und "wie man Templates benutzen kann". Seit Jahren basieren meine Higher-Level Entwicklungen fast nur noch auf dem eigenen Krams. Bitte NICHT nach dem Sinn fragen .. den gibt es nicht: Eben nur "weil ich es kann". Im Berufsleben bin ich nach 10 Jahren Entwicklung ins User Department im Konzernumfeld gewechselt und würde jedem Entwickler/IT-Projektleiter, der uns vorschlägt, das Rad neu zu erfinden [wie ich es auch gerne mache ;-)], sofort die Finger und Beine brechen (lassen). Dort ist das Leben ergebnisorientierter. Aber Daheim gönne ich mir den Luxus des "selbst frickelns" zu meiner persönlichen Entspannung. Die Frage ist auch, warum bauen wir Spiele - wir könnten ja welche kaufen. Warum spielen wir? Wir könnten ja nen Film gucken. Aus meiner Sicht ist die Grenze zum "Warum" (im Hobbybereich) völlig willkürlich. ;-) Ich trenne da bewusst Beruf und Hobby.
Spiele Programmierer hat geschrieben:Nur Linked Lists kann man damit nicht darstellen: Allerdings die passen in dein "TBaseCollection" Interface eben so wenig und in der Regel lässt man eh besser die Finger von Linaked Lists.
Siehste ... ich kann das. Hashmaps auch (zumindest für die Values - Keys ignoriere ich in meinem Universum großzügig). Du siehst hier ja nur exemplarischen Code...
Spiele Programmierer hat geschrieben: Weil dir scheinbar sehr viel an der Meinung von Stroustrup liegt: In den C++ Core Guidelines empfiehlt er diese Klasse und ich habe irgendwo mal ein Video von ihm gesehen, in dem er sich darüber aufgeregt hat das diese einfache Klasse es noch nicht in die STL geschaft hat.
Was heisst "viel dran liegen". Ich unterstelle ihm, dass er sich als "Erfinder der Sprache" eben mit den vielen Details schon beschäftigt hat, über die "ich" erst Jahre später stolpere. Cool, danke! Da schau ich mir mal an. Thx!

Mir ist nur wichtig, zu wissen, wenn ich hier "technisch kompletten Bullshit" gebaut hätte...
--
Verallgemeinerungen sind IMMER falsch.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Top-OR hat geschrieben:
Spiele Programmierer hat geschrieben:Nur Linked Lists kann man damit nicht darstellen: Allerdings die passen in dein "TBaseCollection" Interface eben so wenig und in der Regel lässt man eh besser die Finger von Linaked Lists.
Siehste ... ich kann das. Hashmaps auch (zumindest für die Values - Keys ignoriere ich in meinem Universum großzügig). Du siehst hier ja nur exemplarischen Code...
Würd mich interessieren, wie genau du das machst. Ich seh jedenfalls keinen sinnvollen Weg, sequentielle und assoziative Container hinter ein gemeinsames Interface zu packen. Was auch immer für eine technische Lösung du dafür gestickt haben magst, sowas ist auf konzeptioneller Ebene völlig daneben... ;)
Top-OR hat geschrieben:
Spiele Programmierer hat geschrieben: Weil dir scheinbar sehr viel an der Meinung von Stroustrup liegt: In den C++ Core Guidelines empfiehlt er diese Klasse und ich habe irgendwo mal ein Video von ihm gesehen, in dem er sich darüber aufgeregt hat das diese einfache Klasse es noch nicht in die STL geschaft hat.
Was heisst "viel dran liegen". Ich unterstelle ihm, dass er sich als "Erfinder der Sprache" eben mit den vielen Details schon beschäftigt hat, über die "ich" erst Jahre später stolpere. Cool, danke! Da schau ich mir mal an. Thx!

Mir ist nur wichtig, zu wissen, wenn ich hier "technisch kompletten Bullshit" gebaut hätte...
Hängt davon ab, was du unter "technisch" verstehst. Es ist soweit korrekt als dass es korrektes C++ ist. Besonders toll ist es aber nicht... ;)
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

dot hat geschrieben:Würd mich interessieren, wie genau du das machst. Ich seh jedenfalls keinen sinnvollen Weg, sequentielle und assoziative Container hinter ein gemeinsames Interface zu packen.
Echt nicht? Du kannst du nicht vorstellen, dass man für eine Menge von gleichen und diskreten Objekten eine Halbordnungsrelation definiert, denen diese Objekte genügen und anhand der du dann ein „>, „<“ oder ein „==“ ausführen kannst?
Da kannste doch alles nehmen, vorzusweise etwas, was den technischen Interna des Containers nahe steht und was deterministisches Verhalten an den Tag legt. Ich glaube, ich würde sogar auf einem Container Namens CAlterSchrankAufDemDachbodenMitKramsDrinne eine brauchbare Abzähllogik definieren, die sich deterministisch verhält. Wenn du die hast, ist auch operator[] kein Problem mehr. getCount() sowieso nicht.

Wenn du das kannst, kannst du sie auch abzählen und sie kommen bei jedem „Abzählvorgang“ in der gleichen Reihenfolge.

So kann man zumindest eine Hashmap gut leersaugen bzw. ändern. Neu befüllen geht natürlich (bei Hashmaps) nicht, es sei denn, man denkt sich beim Befüllen der Values aus einer Liste noch Keys aus. Das wäre aber wirklich "blöd". Sowas wie "Listenobjekt = HashmapObjekt" kann ich, "HashmapObjekt = Listenobjekt" nicht, da Informationen fehlen.
dot hat geschrieben:Was auch immer für eine technische Lösung du dafür gestickt haben magst, sowas ist auf konzeptioneller Ebene völlig daneben... ;)
Für mich als User des Frameworks fühlt sich nicht so schlimm an. ;-)
dot hat geschrieben:Hängt davon ab, was du unter "technisch" verstehst. Es ist soweit korrekt als dass es korrektes C++ ist. Besonders toll ist es aber nicht... ;)
Ich mags ... Ich wäre nur beunruhigt, wenn es aufgrund des Thread-Themas nur "zufällig" funktionieren würde, weil etwas passiert, was eigentlich "garnicht gehen sollte". "Fachlich" (als Konsument meines eigenen Dogfoods) bin ich zufrieden.
--
Verallgemeinerungen sind IMMER falsch.
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: C++ Templates und virtuelle Methoden

Beitrag von Spiele Programmierer »

Ne, ich glaube, einer von uns beiden versteht den anderen gerade nicht (nicht zynisch gemeint).
Es geht darum, dass die Implementierungen, die auch der Collection arbeiten, nur das Interface (abstrakte Basisklasse unter TCollection, quasi ICollection) kennen und damit operieren. Es geht nicht darum, dass die Methoden "nur gleich heissen", dass ich sie besser verstehe.
Ne, das kann man auch mit einem gleichen Interface erreichen.
Der einzige Unterschied ist, dass die Polymorphie dann statisch und nicht dynamisch stattfindet. Weil C++ immer noch keine Concepts hat, wirkt das auf den ersten Blick etwas fragil, aber es funktioniert gut und hat den großen Vorteil das es eben statisch ist. Schau dir zum Beispiel alle Dinge in algorithm an. Die funktionieren auch mit jedem Container und das ganz ohne virtual call overhead. (Der pro Iterator schon extrem groß wäre)
Für diesen Zweck würde ich dir eine einfache "array_view" Klasse nahelegen.
Ja, sowas habe ich auch,
Warum nutzt es dann nicht auch für diesen Zweck? Was ist der Sinn?
Ich bin mir sogar ziemlich sicher, dass es in den aller meisten Fällen performanter wäre eine Hash Map für einen Call in einen Vector zu kopieren, anstatt durch die Hashmap mit virtual Calls zu gehen.
Nur Linked Lists kann man damit nicht darstellen: Allerdings die passen in dein "TBaseCollection" Interface eben so wenig und in der Regel lässt man eh besser die Finger von Linaked Lists.
Siehste ... ich kann das
Manchmal ist nicht unbedingt positiv bestimmte Dinge zu können.
Besonders wenn der allgemeine Fall so massiv leidet.
Mir ist nur wichtig, zu wissen, wenn ich hier "technisch kompletten Bullshit" gebaut hätte...
Nunja - es ist valides C++, ja.
Wenn dir darum geht, ob es sinnvoll ist, dann nein.

Wenn es nur dein Hobby ist, dann "darfst" du das natürlich machen.
Aber dann darfst du nicht gleichzeitig in einem Forum fragen und dich für die Meinung des "Erfinders der Sprache" interessieren. ;-)
Zuletzt geändert von Spiele Programmierer am 05.08.2016, 14:56, insgesamt 1-mal geändert.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Top-OR hat geschrieben:
dot hat geschrieben:Würd mich interessieren, wie genau du das machst. Ich seh jedenfalls keinen sinnvollen Weg, sequentielle und assoziative Container hinter ein gemeinsames Interface zu packen.
Echt nicht? Du kannst du nicht vorstellen, dass man für eine Menge von gleichen und diskreten Objekten eine Halbordnungsrelation definiert, denen diese Objekte genügen und anhand der du dann ein „>, „<“ oder ein „==“ ausführen kannst?
Ich kann mir nicht vorstellen, wie indizierter Zugriff auf einen durch eine solche Halbordnungsrelation definierten Container aussehen soll, denn eine der Eigenschaften einer Halbordnung ist ja gerade, dass es eben keine totale Ordnung gibt und sich so etwas wie ein Index gar nicht erst eindeutig definieren lässt. Abgesehen von der mangelnden Sinnhaftigkeit ist indizierter Zugriff für solche Container in der Regel zusätzlich auch nicht effizient implementierbar... ;)
Top-OR hat geschrieben:Da kannste doch alles nehmen, vorzusweise etwas, was den technischen Interna des Containers nahe steht und was deterministisches Verhalten an den Tag legt. Ich glaube, ich würde sogar auf einem Container Namens CAlterSchrankAufDemDachbodenMitKramsDrinne eine brauchbare Abzähllogik definieren, die sich deterministisch verhält. Wenn du die hast, ist auch operator[] kein Problem mehr. getCount() sowieso nicht.

Wenn du das kannst, kannst du sie auch abzählen und sie kommen bei jedem „Abzählvorgang“ in der gleichen Reihenfolge.
Außer ich füge ein neues Element in den Container ein oder entferne ein vorhandenes, denn dann werden alle dieser "Indices" zwangsweise ungültig, da sie nur für eine gegebene Menge an Elementen definierbar sind. Genau da liegt ja der Unterschied zwischen einem sequentiellen und einem assoziativen Container... ;)
Top-OR hat geschrieben:
dot hat geschrieben:Hängt davon ab, was du unter "technisch" verstehst. Es ist soweit korrekt als dass es korrektes C++ ist. Besonders toll ist es aber nicht... ;)
Ich mags ... Ich wäre nur beunruhigt, wenn es aufgrund des Thread-Themas nur "zufällig" funktionieren würde, weil etwas passiert, was eigentlich "garnicht gehen sollte". "Fachlich" (als Konsument meines eigenen Dogfoods) bin ich zufrieden.
Nun, dann kannst du beruhigt sein, undefiniertes Verhalten hast du mit obigem Konstrukt keines. Gutes C++ ist es aber definitiv nicht.
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

Moment, moment, moment. Ich verstehe, ehrlich gesagt, immer weniger, was Ihr sagen wollt. (Nicht zynisch gemeint). Sehe ich das richtig, dass Ihr mir sagen wollt, dass:

1) ... die Idee, sequentiell durch z.B. Hashmaps oder Dachbodenschränke (zum Lesen und Value-Mamipulation) zu iterieren, blödsinnig ist?
oder
2) ... mein Ansatz, das mit einem gemeinsamen (Minimal-)Interface umzusetzen (welches ja nur zusätzlich zu den oft und am meisten genutzten containerspezifischen Zugriffsmethoden zur Verfügung steht), unglücklich ist und ich andere Sprachkonstrukte nutzen sollte?
oder
3) Lieber die fertigen Container verwenden sollte?
Zuletzt geändert von Top-OR am 05.08.2016, 15:43, insgesamt 1-mal geändert.
--
Verallgemeinerungen sind IMMER falsch.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Top-OR hat geschrieben:Sehe ich das richtig, dass Ihr mir sagen wollt, dass:

1) Das die Idee, sequentiell durch z.B. Hashmaps oder Dachbodenschränke (zum Lesen und Value-Mamipulation) zu iterieren, blödsinnig ist?
Per Index auf Hashmaps oder Dachbodenschränke zugreifen ist sinnlos. Iterieren ist was Anderes und hat nix mit einem Index oder [] Operator zu tun... ;)
Top-OR hat geschrieben:2) Das mein Ansatz, das mit einem gemeinsamen (Minimal-)Interface umzusetzen (welches ja nur zusätzlich zu den oft und am meisten genutzten containerspezifischen Zugriffsmethoden zur Verfügung steht), unglücklich ist [...]
exactly
Top-OR hat geschrieben:3) Lieber die fertigen Container verwenden sollte?
Es geht nur darum, dass die fertigen Container nicht ohne Grund eben kein gemeinsames Interface für sequentielle und assoziative Container haben. Eben genau weil das keinen Sinn macht... ;)
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: C++ Templates und virtuelle Methoden

Beitrag von Spiele Programmierer »

Es geht nur darum, dass die fertigen Container nicht ohne Grund eben kein gemeinsames Interface für sequentielle und assoziative Container haben.
Naja "empty", "size", "begin", "end" und ein paar andere haben sie in gewisser Weise schon gemeinsam.

Das in solche virtuellen Schnittstellen zu zwängen, halte ich trotzdem für sehr unsinnig.
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Helmut »

dot hat geschrieben:
Top-OR hat geschrieben:3) Lieber die fertigen Container verwenden sollte?
Es geht nur darum, dass die fertigen Container nicht ohne Grund eben kein gemeinsames Interface für sequentielle und assoziative Container haben. Eben genau weil das keinen Sinn macht... ;)
Es macht schon Sinn und Top-OR hat im Grunde mit seiner Lösung die Standardbibliothek von Java nachprogrammiert. Das Problem ist, dass der Geschwindigkeitsverlust durch die Polymorphie nicht zu unterschätzen ist. Im besten Fall hat man mit der Lösung pro iteriertem Element einen vtable call, in der Praxis also einen Chachemiss. Da CPUs heutzutage im Wesentlichen den Flaschenhals im Speicherzugriff haben, hat das im Endeffekt die Folge, dass sich die Geschwindigkeit in der Iteration mindestens halbiert. Zusätzlich hat der Compiler auch in der Praxis keine Chance, da etwas zu inlinen.

Das ist auch mMn der Hauptgrund, weshalb Javaprogramme so langsam sind.
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

dot hat geschrieben:Per Index auf Hashmaps oder Dachbodenschränke zugreifen ist sinnlos
Das glaube ich nicht, Tim. Für mich ist das eine fachliche Entscheidung, das zumindest tun zu können. Natürlich muss man sich über die Rahmenbedingungen (Performance, Konstanz in welchem Kontext, Reproduzierbarkeit) im Klaren sein.

Wiederholtes Iterieren und das damit assoziierbare Verknüpfen der Iterations-Ergebnisse mit numerischen Indices finde ich jetzt nicht so arg auseinander.
Wo in einer Menge (z.B. mit den Elementen "rot", "grün" und "blau") ist denn der "begin()"? Ist DAS fachlich eleganter/sinnvoller? Echt jetzt?

Für mich ist es nicht sinnlos, ist aber zugegeben ein Edge-Case und die sich ergebenden (willkürlichen) (Halb-)Ordnungen haben natürlich keine "allgemeingültige fachliche Eleganz", sind aber vorhanden, konstant, reproduzierbar und ich kann mich mit ihnen abfinden.

Wenn ich eine Hashmap benutze, dann ja, weil ich PRIMÄR schnelles Auflösen von Keys ind die Values brauche und nicht, weil ich den ganzen Tag per Index drüber iterieren oder per Index "random accessen" möchte (und wenn, dann nur in bestimmten Fällen). Sollte eigentlich klar sein...

Entstanden ist die Idee mit dem Index vor ein paar Jahren, wo ich beruflich mehr mit Perl und PHP unterwegs war. Ich glaube, in Javascript geht das auch. Weiß nicht mehr so genau...

Der Behauptung, dass das "sinnlos" ist, schließe ich mich daher nicht an. Ob es "gutes" C++ im Sinne der kaiserlichen Tradition ist, ist mir wieder egal, wenn es "valide und nicht mehrdeutig" ist.

Der Grund, warum ich dann doch nach "Best Practices" frage, ist, da ich verstehen möchte, warum manche "Verallgemeinerten Do's and Dont's" so sind, wie sie sind. Oft hat das praktische und komplexe Gründe, die eben in verallgemeinerten einfachen Regeln münden, um sie greifbarer zu machen.

Und so schaue ich eben mal genau nach, um eben am Ende besser abzuwägen, was die Konsequenzen sind, falls ich sie ignoriere... ;-) Trading eben.

dot hat geschrieben:exactly
Spiele Programmierer hat geschrieben:Für diesen Zweck würde ich dir eine einfache "array_view" Klasse nahelegen.
Darüber würde ich gerne mehr reden. Deswegen danke nochmal für den Hinweis zum Konzept "array_view" und dessen korrekte Benutzung...
Ich lasse mich da mal inspirieren.
Spiele Programmierer hat geschrieben:Das in solche virtuellen Schnittstellen zu zwängen, halte ich trotzdem für sehr unsinnig.
Wie gesagt - Danke für den Denkanstoß. Ich lasse mir mal durch den Kopf gehen...
Zuletzt geändert von Top-OR am 05.08.2016, 17:59, insgesamt 4-mal geändert.
--
Verallgemeinerungen sind IMMER falsch.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Helmut hat geschrieben:
dot hat geschrieben:
Top-OR hat geschrieben:3) Lieber die fertigen Container verwenden sollte?
Es geht nur darum, dass die fertigen Container nicht ohne Grund eben kein gemeinsames Interface für sequentielle und assoziative Container haben. Eben genau weil das keinen Sinn macht... ;)
Es macht schon Sinn und Top-OR hat im Grunde mit seiner Lösung die Standardbibliothek von Java nachprogrammiert.
Nö, die Java Standardbibliothek macht genauso einen Unterschied zwischen sequentiellen und assoziativen Containern...
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Top-OR hat geschrieben:Wiederholtes Iterieren und das damit assoziierbare Verknüpfen der Iterations-Ergebnisse mit numerischen Indices finde ich jetzt nicht so arg auseinander.
Doch, denn das Konzept "iterieren" und das Konzept "Index" haben nichts miteinander zu tun. Ein Index markiert die Stelle an der ein Objekt in einer Sequenz anzufinden ist. Gibt es keine Sequenz, gibt es keinen Index. Iterieren kann ich ganz abstrakt auch über Mengen von Objekten, denen keine sequentielle Struktur zugrunde liegt, beim Konzept der Iteration über eine Collection geht es nur darum, jedes Element einmal zu besuchen, ganz egal in welcher Reihenfolge dies passiert. Ich kann auch parallel iterieren, in diesem Fall gibt es dann selbst eine dem Vorgang der Iteration an sich anhaftende Reihenfolge nicht mehr...
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

dot hat geschrieben:
Top-OR hat geschrieben:Wiederholtes Iterieren und das damit assoziierbare Verknüpfen der Iterations-Ergebnisse mit numerischen Indices finde ich jetzt nicht so arg auseinander.
Doch, denn das Konzept "iterieren" und das Konzept "Index" haben nichts miteinander zu tun. Ein Index ist markiert die Stelle an der ein Objekt in einer Sequenz anzufinden ist. Gibt es keine Sequenz, gibt es keinen Index. Iterieren kann ich auch über Mengen von Objekten, denen keine sequentielle Struktur zugrunde liegt, beim Konzept der Iteration über eine Collection geht es nur darum, jedes Element einmal zu besuchen.
Aber während des Herausholens erzeugst du eine Sequentialität, die du dann auch mal nummerieren könntest...
Du holst das "erste" heraus, das nennst du 0.
Du holst das "zweite" heraus, das nennst du 1.
...

Das das nicht auf Gedeih und Verderb per Natur-, mathematischem und logischem Gesetz miteinander verknüpft ist, ist mir klar, aber es liegt (mir) nahe.
--
Verallgemeinerungen sind IMMER falsch.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von dot »

Top-OR hat geschrieben:
dot hat geschrieben:
Top-OR hat geschrieben:Wiederholtes Iterieren und das damit assoziierbare Verknüpfen der Iterations-Ergebnisse mit numerischen Indices finde ich jetzt nicht so arg auseinander.
Doch, denn das Konzept "iterieren" und das Konzept "Index" haben nichts miteinander zu tun. Ein Index ist markiert die Stelle an der ein Objekt in einer Sequenz anzufinden ist. Gibt es keine Sequenz, gibt es keinen Index. Iterieren kann ich auch über Mengen von Objekten, denen keine sequentielle Struktur zugrunde liegt, beim Konzept der Iteration über eine Collection geht es nur darum, jedes Element einmal zu besuchen.
Aber während des Herausholens erzeugst du eine Sequentialität, die du dann auch mal nummerieren könntest...
Du holst das "erste" heraus, das nennst du 0.
Du holst das "zweite" heraus, das nennst du 1.
...

Das das nicht auf Gedeih und Verderb per Natur-, mathematischem und logischem Gesetz miteinander verknüpft ist, ist mir klar, aber es liegt (mir) nahe.
dot hat geschrieben:Ich kann auch parallel iterieren, in diesem Fall gibt es dann selbst eine dem Vorgang der Iteration an sich anhaftende Reihenfolge nicht mehr...
Durch einführen solcher willkürlichen Abhängigkeiten schränkst du infolge der daraus resultierenden Vermischung der dahinterstehenden Konzepte die Mächtigkeit deiner Abstraktion völlig unnötig ein... ;)
Benutzeravatar
Top-OR
Establishment
Beiträge: 330
Registriert: 02.03.2011, 16:32
Echter Name: Jens H.
Wohnort: Esslingen/Dessau
Kontaktdaten:

Re: C++ Templates und virtuelle Methoden

Beitrag von Top-OR »

dot hat geschrieben:Ich kann auch parallel iterieren, in diesem Fall gibt es dann selbst eine dem Vorgang der Iteration an sich anhaftende Reihenfolge nicht mehr...
Wenn es nur lesend ist, sehe ich kein Problem. Aber selbst das kann ich bisher in der Codebase von ~80.000 Zeilen ausschließen.
dot hat geschrieben:Durch aufzwingen solcher willkürlichen Abhängigkeiten und vermischen der dahinterstehenden Konzepte, schränkst du deine Abstraktionen völlig unnötig ein... ;)
Damit kommen wir der Sache schon Näher. Ich möchte auch keine akademische Diskussion hier.
Ich denke, wir stimmen überein, dass es nicht die beste Möglichkeit der Welt ist, an die Elemente zu kommen, aber ich habe zumindest Fälle, wo es "irgendwie schön ist", abstrakt per Zahl zu indizieren. Im Gegensatz zu den Möglichkeiten, Parallel zu "index/random accessen" (was bisher nicht gemacht wird): Wenn einer wirklich per numerischem Index zugreifen muss, macht er das alleine und bitte auch nicht so oft. Die Performance... ihr wisst.

Am Ende reden wir hier nicht über die "alleinige Möglichkeit", an die Elemente zu kommen, sondern über einen Edge-Case. (dachte, das käme rüber)
Wenn ein "Konsument weiß", dass es z.B. eine Hashmap ist, kann auch offiziell ohne numerischen Index schnell gehashmapped werden.

Achso: Ursprünglich gings mir auch eher mal darum, die Interfaces von Listen und Arrays und anderem "linearen" Krams zu harmonisieren. Das ich das auch den Hashmaps aufgedrückt habe, ist eher ein Seiteneffekt. ;-)
--
Verallgemeinerungen sind IMMER falsch.
Antworten