Optimierbar?
-
Dravere schrieb:
Da hast du Shade Of Mine, glaub ich, falsch verstanden. Ein Leser des Codes, also z.B. ein anderer Entwickler, ist nicht daran interessiert, was für ein Container hier verwendet wird. Dies Information ist überflüssig zum Verständnis des Programmcodes.
Ja, zum reinen Lesen geht das ja vielleicht noch. Aber wenn man selber dran weiterarbeitet, sollte man auch wissen, was der Container so kann.
Und:
Dravere schrieb:
Und man sollte eigentlich fast immer damit rechnen, dass sich der Container verändern könnte. Und da bist du besser abgesichert, mit solch einer Lösung.
Das heisst, bei allen Containern sollte man nicht mehr als durchiterieren und Random Access mit
std::advance()durchführen, damit es auch bei einer Liste geht?Meiner Ansicht nach sollte man sich irgendwann für einen Containertypen entscheiden, damit man auch dessen spezifische Vorteile nutzen kann.

-
Nexus schrieb:
Ja, zum reinen Lesen geht das ja vielleicht noch. Aber wenn man selber dran weiterarbeitet, sollte man auch wissen, was der Container so kann.
Wenn man dran arbeitet, hat man das normalerweise im Kopf. Wenn man es nicht mehr im Kopf hat, kennt man wahrscheinlich auch den Code nicht mehr und muss ihn lesen, was auch problemlos geht.
Und um den Typ dann noch schnell rauszufinden, gibt es entsprechende Suchfunktionen. Viele IDEs bieten da auch Dinge an, wie: "Goto Definition/Declaration" oder ähnliches.Nexus schrieb:
Das heisst, bei allen Containern sollte man nicht mehr als durchiterieren und Random Access mit
std::advance()durchführen, damit es auch bei einer Liste geht?Vielfach ist das sogar tatsächlich am besten. Klar sollte man sich einmal auf einen Container definieren, aber man bleibt halt flexibler, wenn man es so löst. Die berühmte Wartbarkeit wird meiner Meinung nach dadurch erhöht.
Grüssli
-
Warum ist es wichtig ob der Container ein vector, eine list oder deque ist wenn er meine Anforderungen erfüllt? Dafür haben wir ja das iteratoren Konzept.
natürlich ist es an einer gewissen stelle wichtig welche implementierung der container verwendet - aber die meiste zeit ist das egal. ich sage einfach find(c.begin(), c.end(), v) und bekomme das gesuchte Elemente. selbes bei for_each oder sonstigen schleifen -> relevant wird es nur wenn ich den container bearbeite. und auch dann sind nur die groben constraints interessant (habe wie komplex sind die insert/remove operationen).
-
Dravere schrieb:
Wenn man dran arbeitet, hat man das normalerweise im Kopf. Wenn man es nicht mehr im Kopf hat, kennt man wahrscheinlich auch den Code nicht mehr und muss ihn lesen, was auch problemlos geht.
Und um den Typ dann noch schnell rauszufinden, gibt es entsprechende Suchfunktionen. Viele IDEs bieten da auch Dinge an, wie: "Goto Definition/Declaration" oder ähnliches.Den Typen herauszufinden ist auch nicht das Problem. Normalerweise reicht ein Darüberfahren mit der Maus, wie schon Shade Of Mine sagte. Aber ich kann mir vorstellen, das es sehr viele Fälle gibt, wo man so ein
container_t-Typedef macht, und dann den Typen trotzdem nicht ändert. Da wäre es vielleicht ein wenig effizienter, wenn man gleich den Typen sähe (auch wenn das nicht viel ausmacht).Dravere schrieb:
Vielfach ist das sogar tatsächlich am besten. Klar sollte man sich einmal auf einen Container definieren, aber man bleibt halt flexibler, wenn man es so löst. Die berühmte Wartbarkeit wird meiner Meinung nach dadurch erhöht.
Schon wieder so ein Standardargument :p
Was aber im Gegensatz zur guten Planung im Voraus und zum sauberen Design steht
Sorry, aber wenn man auf einer
std::listmitstd::advance()den Random-Access hinbiegen will, kann man ja gleich zustd::vectorgreifen. Oder zustd::deque, das ist noch flexibler. Kommt es so häufig vor, dass man im Voraus nicht sagen kann, wie der Container gebraucht wird und welche Funktionalität er bieten soll?Shade Of Mine schrieb:
Warum ist es wichtig ob der Container ein vector, eine list oder deque ist wenn er meine Anforderungen erfüllt? Dafür haben wir ja das iteratoren Konzept.
Ja eben, bei einfachem Durchiterieren und allgemein gehaltenen Operationen ist das ja kein Problem. Aber wieso haben die einzelnen STL-Container (reden wir von den 3 sequenziellen) Unterschiede? Wohl eher nicht, damit man alles allgemein hinbiegt (
std::advance()undinsert(begin())stattpush_front()). Klar kann es Fälle geben, in denen es nicht drauf an kommt, welchen Container man nimmt. Aber zumindest in den anderen Fällen finde ich ein Typedef unnötig.
-
Nexus schrieb:
Aber wieso haben die einzelnen STL-Container (reden wir von den 3 sequenziellen) Unterschiede? Wohl eher nicht, damit man alles allgemein hinbiegt (
std::advance()undinsert(begin())stattpush_front()). Klar kann es Fälle geben, in denen es nicht drauf an kommt, welchen Container man nimmt. Aber zumindest in den anderen Fällen finde ich ein Typedef unnötig.Es ist immer wichtig welchen Container man nimmt, es ist nur nicht immer wichtig

Was ich damit sagen will ist, dass die Entscheidung wichtig ist, aber der Client Code, dem ist das herzlichst egal. Die komplette c++ standard library ist so aufgebaut: gib mir 2 iteratoren und ich mache meinen job - egal welcher container zugrunde liegt.
und von wenigen code stücken abgesehen, ist es egal welche container man verwendet. man operiert die meiste zeit auf iteratoren - interessant ist das ganze nur in den kurzen momenten wo ich den container befülle oder rauslösche (oder ähnliche operationen mache). aber die meiste zeit suche ich etwas, transformiere etwas, manipuliere etwas,... und dafür ist der container egal. das ist die ganze idee dahinter.
uU will man auch einfach eine list verwenden und dann später mal einen benchmark mit einer single linked list testen und uU noch etwas später mal sehen wie es mit einer deque performt...
-
Aber wieso haben die einzelnen STL-Container (reden wir von den 3 sequenziellen) Unterschiede? Wohl eher nicht, damit man alles allgemein hinbiegt (std::advance() und insert(begin()) statt push_front()).
Ich kann es atm leider nicht überprüfen, aber ich würde mal behaupten, dass die STL das eh mit Spezialisierung löst, dass die passenden Funktionen aufgerufen werden.
-
Shade Of Mine schrieb:
man operiert die meiste zeit auf iteratoren - interessant ist das ganze nur in den kurzen momenten wo ich den container befülle oder rauslösche (oder ähnliche operationen mache). aber die meiste zeit suche ich etwas, transformiere etwas, manipuliere etwas,... und dafür ist der container egal. das ist die ganze idee dahinter.
Hm, das leuchtet ein. Aber zumindest für den kurzen Moment spielt das schon eine Rolle
- naja, bei meinen Anwendungen von Containern war es eben eher so, dass z.B. erase()-Operationen oder Random Access nicht selten vorkommen. Ich versuche auch von Anfang an, den am besten geeigneten Container einzusetzen und gebe dafür halt einen Teil der Flexibilität auf. Im Übrigen ist es bei meinen Projekten noch im Bereich des Möglichen, Containertypen auszuwechseln (auch wenn es kaum vorkommt). Deshalb der Einwand. Ausserdem bin ich kritisch gegenüber Argumenten wie besserer Wartbarkeit/mehr Flexibilität, die teilweise auf Kosten der Übersicht gehen und oft gar nie in der Praxis zur Geltung kommen.drakon schrieb:
Ich kann es atm leider nicht überprüfen, aber ich würde mal behaupten, dass die STL das eh mit Spezialisierung löst, dass die passenden Funktionen aufgerufen werden.
Ja, also wegen der Performance wirds kaum einen wesentlichen Unterschied machen... Beispielsweise wird ja bei
std::advance()nach Möglichkeit deroperator+verwendet, und sonst eben n Maloperator++. Ich meinte nur, man könne ja direkt die dafür vorgesehenen Funktionen verwenden, wenn der Container feststeht. Und meiner Ansicht nach sollte es auch nicht sehr häufig vorkommen, das man am Anfang den Container noch nicht festlegen kann.
-
Nexus schrieb:
Aber ich kann mir vorstellen, das es sehr viele Fälle gibt, wo man so ein
container_t-Typedef macht, und dann den Typen trotzdem nicht ändert. Da wäre es vielleicht ein wenig effizienter, wenn man gleich den Typen sähe (auch wenn das nicht viel ausmacht).Das habe ich sehr oft, dass ich am Ende nichts daran ändere. Aber man macht es trotzdem so, damit im Falle der Fälle ...

Ich mache bei Logikfehlern und anderem auchasserts in den Code rein. Die sind ja eigentlich unnötig, wenn man die Bibliothek oder das Programm richtig benutzt, dann funktioniert es doch. Trotzdem leistet man sich diese zusätzliche Schreibarbeit
Nexus schrieb:
Was aber im Gegensatz zur guten Planung im Voraus und zum sauberen Design steht

Man kann NIE alles planen! Das gilt im übrigen nicht nur in der Programmierung

Nexus schrieb:
Kommt es so häufig vor, dass man im Voraus nicht sagen kann, wie der Container gebraucht wird und welche Funktionalität er bieten soll?
Es geht schliesslich nur um das "falls". Zudem erhöht es an sich die Übersicht sogar. Ich finde so Templateklassen extrem mühsam zu lesen.
std::vector<unsigned int> <-> IndexContainer_tUnd es ist dann auch viel einfacher zu schreiben:
std::vector<unsigned int>::iterator iter = // ... std::vector<unsigned int>::iterator end = // ... // <-> IndexContainer_t::iterator iter = // ... IndexContainer_t::iterator end = // ...Und dieses Argument gibt es auch noch:
Shade Of Mine schrieb:
uU will man auch einfach eine list verwenden und dann später mal einen benchmark mit einer single linked list testen und uU noch etwas später mal sehen wie es mit einer deque performt...
Und noch eine Sache gibt es. Wenn du das ganze als Teil einer Bibliothek auslieferst und du plötzlich den Container wechselst, dann zerschiesst du die Anwendungen aller jener, welche die Lib benutzen. Und gerade bei sowas, kann es durchaus vorkommen, dass man mal einen anderen Container nimmt. Vielleicht von den Standard-Container weg will, um eine bessere Version einzubauen, eine eigene oder ähnliches.
Aber naja, wie du es selbst sagst. Bei deinen "kleinen" Anwendungen ist es vielleicht noch kein Problem, wenn du den Container wechselst und du nur an 5 Stellen etwas anders schreiben gehen musst. Wenn du aber plötzlich an hunderten Stellen etwas umschreiben musst, dann wirst du dir wünschen, dass du es damals anders gelöst hättest.
Und man soll sich eben auch schon bei kleinen Projekten an sowas gewöhnen. Was Fritzchen nicht lernt, lernt er nimmer mehr ... oder so ähnlich ging das doch?
Grüssli
-
*lol* Thread-hijacking vom Feinsten

cheers, Swordfish
BTW: Ich bin (auch) für die
typedef-Variante.
-
Auf jeden Fall die typedef-Variante. Das steigert die Abstraktion.
-
Was soll denn immer das gerede von "kleinen" Anwendungen?
Bis zu einer gewissen größe kann ich auch alles in die main schreiben oder rein funktional Programmieren.
Das Ziel in dem Forum ist doch nicht die minimale Lösung, sondern die optimale Lösung.
-
templäd schrieb:
Bis zu einer gewissen größe kann ich auch alles in die main schreiben oder rein funktional Programmieren.
Leute, lernt endlich mal, dass es einen wichtigen Unterschied zwischen funktional und prozedural gibt.