C notwendig für C++?



  • Dobi schrieb:

    C sind Grundlagen schrieb:

    Wie will man eine Liste verstehen, wenn man nicht einmal weiß, wie man es in C mit Zeigern realisieren würde?

    Wie will man Zeiger in C verstehen wenn man das sowas nie in Assembler geschrieben hat? Wie will man Assembler verstehen wenn man nie eine CPU designed hat? ... Wie will man Strom verstehen wenn man nie ... 😉

    Der Vergleich hinkt gewaltig.

    Das HighLevel Zeugs von C++ ist so stark abstrahiert, dass der sichtbare Code Meilenweit vom Assemblercode entfernt ist, den der Compiler daraus machen würde.
    Bei C bist du mit Zeigern näher an Assembler als bei C++ mit Objekten.

    Man setzt halt auf irgendeiner Abstraktionsebene an. Es ist manchmal gut wenn man auch die tieferliegenden kennt, aber nicht immer nötig. Das ist ja grad das tolle an Abstraktion solange sie nicht leaky ist. 🙂

    Meiner Meinung nach kann der, der sowieso nicht tiefer unter die Haube nachsehen will auch gleich bei Java oder C# bleiben.

    Du mußt das Zeugs unter der Haube verstehen, um den Sprachumfang von C++ optimal einsetzten zu können.
    Deswegen ist das wichtig.



  • asc schrieb:

    Nutzt ihr Geräte erst, nachdem ihr sie anfangs zerlegt habt? Man kann auch erst das "Nutzen" lernen, bevor man in die Details geht.

    Der Vergleich hinkt.

    Mein Staubsauger funktioniert nämlich auch nicht performanter, wenn ich weiß, wie der unter der Haube arbeitet.
    Bei C++ Code ist das aber anders.

    Xin schrieb:

    Ohne die Grundlagen von C++, die nunmal C komplett ausmachen...

    Dem widerspreche ich schon. Die Grundlagen die man für die sinnvolle C++ Programmierung benötigt, machen C eben nicht komplett aus. Man benötigt nicht Alles was die Sprache C anbietet um gutes C++ zu schreiben.

    performanter C++ Code != guter C++ Code

    Du kannst in C++ den saubersten, d.h. übersichtlichsten und wartbarsten Code unter Verwendung aller HighLevel Features und API Funktionen der STL schreiben, aber das ist dann nicht unbedingt performant.

    Deswegen bleibe ich bei der Aussage, wem es nur um übersichtlichen wartbaren Code geht, der ist höchstwahrscheinlich sogar mit C# oder Java besser bedient.



  • Auskenner schrieb:

    Jockelx schrieb:

    Wenn mit der Frage gemeint ist, ob man pures C beherrschen muss, um C++ zu können, dann von mir ein klares nein!

    Wenn du wissen willst, wie die Objekte in C++ oder das sonstige High Level Zeugs unter der Haube realisiert ist, dann ist es schon sinnvoll, wenn man weiß, wie so etwas in C realisiert werden würde.

    Ja, die Diskussion ist irgendwie doof, weil die Frage auch nicht ganz klar ist.
    Ich finde auch, dass man C-Anteil können sollte.
    Mit 'purem C' können meinte ich so Sachen, wie das mit der Variablendeklaration.
    Wusste ich nicht, dass das in C doch auch später geht, aber dieses fehlende Wissen interessiert mich als C++ler auch kein Stück und läßt meine C++-Programme auch kein Stück schlechter werden.



  • Auskenner schrieb:

    Xin schrieb:

    Ohne die Grundlagen von C++, die nunmal C komplett ausmachen...

    Dem widerspreche ich schon. Die Grundlagen die man für die sinnvolle C++ Programmierung benötigt, machen C eben nicht komplett aus. Man benötigt nicht Alles was die Sprache C anbietet um gutes C++ zu schreiben.

    performanter C++ Code != guter C++ Code

    1. Man muss für C++ keine speziellen C-Kenntnisse besitzen um Performanten Code zu schreiben. Man kann in C++ auch ohne rein in C übliche Konstrukte durchaus schnellen Code schreiben - mag nicht ganz an C heranreichen (wobei dies Fallabhängig durchaus möglich ist), aber "C" seperat muss man dafür nicht lernen.

    Ihr tut so als würden interna in C++ Büchern etc. gänzlich ausgespart. Und das ist falsch. Und ebenso ist C++ nicht per se langsamer als C, sofern man die Fallstricke berücksichtigt (und auch die werden nicht selten in Büchern angesprochen).

    2. Gut und Wartbar steht zwar in teilen der Performance entgegen, aber beileibe nicht immer. Zum anderen meint ihr scheinbar das C-Kenntnisse einen automatisch zu performanteren Code führen. Auch das ist aus Praxiserfahrungen nonsense.

    Spätestens wenn man mit "5 Sterne"-Programmierern gearbeitet hat, weiß man, wovon ich spreche.

    Zum anderen:
    Performance ist sicherlich nicht unwichtig, ein wesentlich wichtigeres Kriterium für eine Software ist aber in der Regel das diese sauber läuft. Man sollte guten und wartbaren Code schreiben, und anschließend prüfen ob und wo zu Optimieren ist. Das heißt nicht das man vorträglich bewusst inperformanten Code schreiben soll, aber das man die Aspekte der Wartbarkeit in Vordergrund stellt. Dies gilt ins besondere, wenn die Software auch lange eingesetzt und weiter entwickelt werden soll (was in meinem Fall zumeist zutrifft, ich bin üblicherweise in der langjährigen Produkt(weiter)entwicklung, nicht der schnelllebigen Projektentwicklung tätig.



  • Jockelx schrieb:

    Ich finde auch, dass man C-Anteil können sollte.

    Was aber auch in der notwendigen Schnittmenge in der Regel in jeden C++ Buch enthalten ist. Das ist der Grund warum ich ein seperates erlernen von C auch völlig unsinnig ansehe.



  • Auskenner schrieb:

    performanter C++ Code != guter C++ Code

    Du kannst in C++ den saubersten, d.h. übersichtlichsten und wartbarsten Code unter Verwendung aller HighLevel Features und API Funktionen der STL schreiben, aber das ist dann nicht unbedingt performant.

    Nein? Warum denn nicht? Einfach nur so, weil es kein C ist? Aha, interessant.



  • DerNewb schrieb:

    Nun hab ich irgendwie das blöde Gefühl, dass ich C erstmal lernen sollte, weil ich in einem Begleitheft zu einem Kurs gelesen habe, dass die Kenntnisse über C vorausgesetzt waren für die Kurse. Nun ... was ist denn jetzt?

    Man kann nicht C++ lernen, ohne auch ein Stückweit C zu lernen, da beide, das wurde ja schon oft in diesem Thread erwähnt, ein gemeinsame Schnittmenge besitzen.

    Entscheidend ist aber, daß der Teil der gemeinsamen Schnittmenge in C++, der gemeinhin als C bezeichnet, formal als C++ definiert ist.

    Und damit kann man auch Klassen oder Container selber bauen.

    Man braucht also C nicht.



  • TyRoXx schrieb:

    Auskenner schrieb:

    performanter C++ Code != guter C++ Code

    Du kannst in C++ den saubersten, d.h. übersichtlichsten und wartbarsten Code unter Verwendung aller HighLevel Features und API Funktionen der STL schreiben, aber das ist dann nicht unbedingt performant.

    Nein? Warum denn nicht? Einfach nur so, weil es kein C ist? Aha, interessant.

    Ich vergesse hier immer, dass nicht jeder in diesem Forum intelligent ist.



  • Auskenner schrieb:

    Ich vergesse hier immer, dass nicht jeder in diesem Forum intelligent ist.

    Grundsätzlich würde mich noch interessieren, wie sich DerNewb nun entschieden hat, aber da er sich an diesem Thread nicht mehr beteiligt war er offenbar intelligent genug. 🙂



  • TyRoXx schrieb:

    Auskenner schrieb:

    performanter C++ Code != guter C++ Code

    Du kannst in C++ den saubersten, d.h. übersichtlichsten und wartbarsten Code unter Verwendung aller HighLevel Features und API Funktionen der STL schreiben, aber das ist dann nicht unbedingt performant.

    Nein? Warum denn nicht? Einfach nur so, weil es kein C ist? Aha, interessant.

    Weil Wartbarkeit/Lesbarkeit gute Performance nicht automatisch impliziert - und vice versa. Egal in welcher Sprache.



  • asc schrieb:

    Man kann in C++ auch ohne rein in C übliche Konstrukte durchaus schnellen Code schreiben - mag nicht ganz an C heranreichen (wobei dies Fallabhängig durchaus möglich ist)

    Welche in C üblichen Konstrukte wären das denn?

    asc schrieb:

    Und ebenso ist C++ nicht per se langsamer als C, sofern man die Fallstricke berücksichtigt (und auch die werden nicht selten in Büchern angesprochen).

    Und die wären?

    Das Thema könnte auch heißen "Plattdeutsch notwendig für Hochdeutsch?".

    Auskenner schrieb:

    Das HighLevel Zeugs von C++ ist so stark abstrahiert, dass der sichtbare Code Meilenweit vom Assemblercode entfernt ist, den der Compiler daraus machen würde.

    Was denn für "High Level Zeugs"?

    Auskenner schrieb:

    Bei C bist du mit Zeigern näher an Assembler als bei C++ mit Objekten.

    Und nachts ist es kälter als draußen.

    Auskenner schrieb:

    Du mußt das Zeugs unter der Haube verstehen, um den Sprachumfang von C++ optimal einsetzten zu können.
    Deswegen ist das wichtig.

    Das Zeugs unter der Haube von C++ ist jedenfalls nicht C.



  • TyRoXx schrieb:

    asc schrieb:

    Man kann in C++ auch ohne rein in C übliche Konstrukte durchaus schnellen Code schreiben - mag nicht ganz an C heranreichen (wobei dies Fallabhängig durchaus möglich ist)

    Welche in C üblichen Konstrukte wären das denn?

    nothrow, reinterpret_cast, for-Loops, if/else, realloc, memcpy, keine Abstraktionen, also Zeiger, etc.

    Das Problem mit den Abstraktionen ist, dass man es nicht fine-tunen kann. Reihenfolge von zwei Destruktoraufrufen umkehren? SSO von std::string abschalten? Nope. Also alle Abstraktionen entfernen und alles eine Stufe low-leveliger schreiben. Aka C.

    TyRoXx schrieb:

    asc schrieb:

    Und ebenso ist C++ nicht per se langsamer als C, sofern man die Fallstricke berücksichtigt (und auch die werden nicht selten in Büchern angesprochen).

    Und die wären?

    Call by reference vs call by value. Unnötige Kopien vs Aliasing-Probleme. Nur mal um ein Fallstrick zu nennen, C++ ist voll davon.

    TyRoXx schrieb:

    Auskenner schrieb:

    Das HighLevel Zeugs von C++ ist so stark abstrahiert, dass der sichtbare Code Meilenweit vom Assemblercode entfernt ist, den der Compiler daraus machen würde.

    Was denn für "High Level Zeugs"?

    virtual, Exceptions, Abstraktion in Bibliotheken (z.Bsp. std::string: Ist für den allgemeinen Fall optimiert, d.h. er ist in keinem Einsatzszenario ideal).

    TyRoXx schrieb:

    Auskenner schrieb:

    Du mußt das Zeugs unter der Haube verstehen, um den Sprachumfang von C++ optimal einsetzten zu können.
    Deswegen ist das wichtig.

    Das Zeugs unter der Haube von C++ ist jedenfalls nicht C.

    Der erste Schritt, C++ zu verstehen, ist, die einzelnen Sprachfeatures in C zu implementieren.



  • fallschritt schrieb:

    TyRoXx schrieb:

    asc schrieb:

    Man kann in C++ auch ohne rein in C übliche Konstrukte durchaus schnellen Code schreiben - mag nicht ganz an C heranreichen (wobei dies Fallabhängig durchaus möglich ist)

    Welche in C üblichen Konstrukte wären das denn?

    nothrow, reinterpret_cast, for-Loops, if/else, realloc, memcpy, keine Abstraktionen, also Zeiger, etc.

    noexcept gibt es in C++. Man kann also durchaus gezielt Exceptions deaktiveren.
    reinterpret_cast ist kein C-Feature.
    for , if , else benutzt man in C++ auch.
    std::vector darf realloc gerne für PODs benutzen.
    memcpy benutzt man in C++ auch. Heißt aber std::copy .
    Abstraktionen nimmt man in C fast genau so wie in C++ vor. Es steht bloß weniger Syntactic Sugar zur Verfügung. Hast du jemals gutes C gesehen?
    Zeiger benutzt man in C++ auch ständig in verschiedenen Varianten.

    fallschritt schrieb:

    Das Problem mit den Abstraktionen ist, dass man es nicht fine-tunen kann.
    Reihenfolge von zwei Destruktoraufrufen umkehren?

    Kann man mit optional machen oder durch swap mit einem Temporary.

    fallschritt schrieb:

    SSO von std::string abschalten? Nope.

    std::vector ? Wenn du es unbedingt brauchst, kannst du auch deinen eigenen String schreiben, der dieselbe Schnittstelle wie std::string implementiert. Kein Problem und völlig normal in C++. Außerdem hat C gar keinen String-Typ, also was hat das mit C zu tun?

    fallschritt schrieb:

    Also alle Abstraktionen entfernen und alles eine Stufe low-leveliger schreiben. Aka C.

    Das nennt man "schlechtes C". In dieser sehr beliebten Programmiersprache ist zum Beispiel OpenSSL geschrieben. Hat super funktioniert.

    fallschritt schrieb:

    Call by reference vs call by value.

    Gibt es in C auch. In C++ ist das überhaupt kein Problem durch die Referenzen.

    fallschritt schrieb:

    Unnötige Kopien vs Aliasing-Probleme. Nur mal um ein Fallstrick zu nennen, C++ ist voll davon.

    Anscheinend so voll, dass du nur insgesamt zwei aufzählen kannst.

    fallschritt schrieb:

    TyRoXx schrieb:

    Auskenner schrieb:

    Das HighLevel Zeugs von C++ ist so stark abstrahiert, dass der sichtbare Code Meilenweit vom Assemblercode entfernt ist, den der Compiler daraus machen würde.

    Was denn für "High Level Zeugs"?

    virtual, Exceptions, Abstraktion in Bibliotheken (z.Bsp. std::string: Ist für den allgemeinen Fall optimiert, d.h. er ist in keinem Einsatzszenario ideal).

    virtual baut man in C ständig so nach, dass exakt der gleiche Code generiert wird. Siehe gutes C.
    Exceptions baut man in C ständig mit if nach.
    Ich wusste auch noch gar nicht, dass der String aus der C-Standardbibliothek für jedes Szenario optimiert ist. Kann auch daran liegen, dass der nicht existiert.

    fallschritt schrieb:

    Der erste Schritt, C++ zu verstehen, ist, die einzelnen Sprachfeatures in C zu implementieren.

    Was genau hat man davon das Nachbauen in C zu machen, wenn man eigentlich C++ lernen möchte? Nach der Logik müsste man C++ eigentlich in BCPL nachbauen. Oder habe ich verpasst, dass aktuelle Prozessoren jetzt direkt C ausführen?



  • std::vector darf realloc gerne für PODs benutzen.

    Nö. std::vector muss seinen allocator verwenden und der hat in seinem Interface kein realloc.



  • Ethon schrieb:

    std::vector darf realloc gerne für PODs benutzen.

    Nö. std::vector muss seinen allocator verwenden und der hat in seinem Interface kein realloc.

    Es ist bestimmt standardkonform den vector für nicht-spezialisierte std::allocator<POD> zu spezialisieren und den Allocator dann zu ignorieren. Oder nicht?



  • TyRoXx schrieb:

    noexcept gibt es in C++. Man kann also durchaus gezielt Exceptions deaktiveren.

    Jo, wenn man dran denkt.

    TyRoXx schrieb:

    reinterpret_cast ist kein C-Feature.

    Die Unterscheidung ist in C++ nur notwendig, weil die Sprache viel zu viele Pitfalls hat.

    TyRoXx schrieb:

    for , if , else benutzt man in C++ auch.

    Nur zählt es dann nicht mehr als schönes C++.

    TyRoXx schrieb:

    std::vector darf realloc gerne für PODs benutzen.

    Nenn mir eine Standardbibliothek die das macht und wir reden weiter. Wieder ein Beispiel für der Performance schädliche Abstraktion.

    TyRoXx schrieb:

    memcpy benutzt man in C++ auch. Heißt aber std::copy .

    Ist aber oft langsamer, weil der Compiler nicht sicher sein kann, ob sich die Bereiche überlappen. (Kann er aber oft in konstruierten Codebeispielen.)

    TyRoXx schrieb:

    Abstraktionen nimmt man in C fast genau so wie in C++ vor. Es steht bloß weniger Syntactic Sugar zur Verfügung. Hast du jemals gutes C gesehen?

    Ja.
    Gutes C: Man erkennt genau, welche Schritte gemacht werden.
    Gutes C++: Sieht fancy aus, aber wie es funktioniert ist magic. Kennst du Boost.Spirit?

    TyRoXx schrieb:

    Zeiger benutzt man in C++ auch ständig in verschiedenen Varianten.

    Wie es auch in C refcounting gibt. Nur hat das Zeigermanagement in C++ viel zu viel Noise für meinen Geschmack. Vor allem die ständigen Konviertierungen mit .get()

    TyRoXx schrieb:

    fallschritt schrieb:

    Das Problem mit den Abstraktionen ist, dass man es nicht fine-tunen kann.
    Reihenfolge von zwei Destruktoraufrufen umkehren?

    Kann man mit optional machen oder durch swap mit einem Temporary.

    Was einen gratis default-Konstruktor voraussetzt. Aber predigt man in C++ nicht, dass Konstruktoren viel Logik enthalten können? Eine std::list z.B. macht im Default-Konstruktor Memory-Allokationen, damit gehen deine Hacks nicht.

    TyRoXx schrieb:

    Wenn du es unbedingt brauchst, kannst du auch deinen eigenen String schreiben, der dieselbe Schnittstelle wie std::string implementiert.

    Viel Spass beim Implementieren von >100 Memberfunktionen.

    TyRoXx schrieb:

    Kein Problem und völlig normal in C++.

    Habe auch das Gefühl, dass C++ sehr viel Boilerplate-Code bedeutet.

    TyRoXx schrieb:

    Außerdem hat C gar keinen String-Typ, also was hat das mit C zu tun?

    Für Immutable-Strings ist const char* ausreichend. Wenn man mehr mit Strings macht hat man sowieso ein GUI-Toolkit oder eine utf8-Library. Kann std::string mittlerweile Unicode?

    TyRoXx schrieb:

    fallschritt schrieb:

    Also alle Abstraktionen entfernen und alles eine Stufe low-leveliger schreiben. Aka C.

    Das nennt man "schlechtes C". In dieser sehr beliebten Programmiersprache ist zum Beispiel OpenSSL geschrieben. Hat super funktioniert.

    Dieser Code in OpenSSL ist einfach schlecht. Aber keine Angst, ich kenne genügend C++-Code der noch schlimmer aussieht. Würdest du auch nicht als schön bezeichnen.

    TyRoXx schrieb:

    fallschritt schrieb:

    Call by reference vs call by value.

    Gibt es in C auch. In C++ ist das überhaupt kein Problem durch die Referenzen.

    In C++ ist das ein Riesenproblem weil unscheinbarer Code riesige Kopien hervorrufen kann. Besonders schlimm ist, dass das Vergessen von " const& " den Code langsamer macht und nicht " const& " der Default ist.

    TyRoXx schrieb:

    fallschritt schrieb:

    Unnötige Kopien vs Aliasing-Probleme. Nur mal um ein Fallstrick zu nennen, C++ ist voll davon.

    Anscheinend so voll, dass du nur insgesamt zwei aufzählen kannst.

    Also eigentlich war das der gleiche Fallstrick nur ein anderer Aspekt.

    TyRoXx schrieb:

    virtual baut man in C ständig so nach, dass exakt der gleiche Code generiert wird. Siehe gutes C.

    Aber in C kann man das besser optimieren. Reihenfolge ändern. Devirtualisierung. Viel einfacher anpassbar als in C++.

    TyRoXx schrieb:

    Exceptions baut man in C ständig mit if nach.

    Exceptions setzt man auch in C++ extrem spärlich ein. Meiner Erfahrung nach kann man problemlos drauf verzichten. Bisschen mehr assert, bei den wenigen verbleibenden Fällen macht man halt ein if, aber das hätte man in C++ genauso gemacht, weil erwarteter Fehler.

    Bei fehlgeschlagenem malloc schreib ich mir ein Handler, da prüfe ich nicht jeden Aufruf.

    fallschritt schrieb:

    Der erste Schritt, C++ zu verstehen, ist, die einzelnen Sprachfeatures in C zu implementieren.

    Was genau hat man davon das Nachbauen in C zu machen, wenn man eigentlich C++ lernen möchte? Nach der Logik müsste man C++ eigentlich in BCPL nachbauen. Oder habe ich verpasst, dass aktuelle Prozessoren jetzt direkt C ausführen?[/quote]
    Es gibt ja so eine Sprachhighleveligkeitskeitskette in der Art: C++ -> C -> BCPL -> ASM
    Je mehr man darüber weiss, wie der Code eine Stufe darunter übersetzt wird, desto besser kann man darüber Performance-Aussagen machen.



  • fallschritt schrieb:

    TyRoXx schrieb:

    memcpy benutzt man in C++ auch. Heißt aber std::copy .

    Ist aber oft langsamer, weil der Compiler nicht sicher sein kann, ob sich die Bereiche überlappen. (Kann er aber oft in konstruierten Codebeispielen.)

    Stimmt, copy entspricht nicht memcpy .

    fallschritt schrieb:

    TyRoXx schrieb:

    Abstraktionen nimmt man in C fast genau so wie in C++ vor. Es steht bloß weniger Syntactic Sugar zur Verfügung. Hast du jemals gutes C gesehen?

    Ja.
    Gutes C: Man erkennt genau, welche Schritte gemacht werden.
    Gutes C++: Sieht fancy aus, aber wie es funktioniert ist magic. Kennst du Boost.Spirit?

    Spirit sähe in C viel schlimmer aus. Man würde gar nichts erkennen.

    fallschritt schrieb:

    TyRoXx schrieb:

    Zeiger benutzt man in C++ auch ständig in verschiedenen Varianten.

    Wie es auch in C refcounting gibt. Nur hat das Zeigermanagement in C++ viel zu viel Noise für meinen Geschmack. Vor allem die ständigen Konviertierungen mit .get()

    Warum brauchst du denn ständig die nackten Zeiger?

    fallschritt schrieb:

    TyRoXx schrieb:

    fallschritt schrieb:

    Das Problem mit den Abstraktionen ist, dass man es nicht fine-tunen kann.
    Reihenfolge von zwei Destruktoraufrufen umkehren?

    Kann man mit optional machen oder durch swap mit einem Temporary.

    Was einen gratis default-Konstruktor voraussetzt. Aber predigt man in C++ nicht, dass Konstruktoren viel Logik enthalten können? Eine std::list z.B. macht im Default-Konstruktor Memory-Allokationen, damit gehen deine Hacks nicht.

    Eigentlich predigt man, dass Konstruktoren gar keine Logik enthalten sollen, sondern höchstens eine Initialisierungsliste, die nur initialisiert.
    std::list sollte man generell nicht verwenden. Im Fall der Liste reicht aber ein clear , um die Elemente freizugeben. Da braucht es keinen kostenlosen Standardkonstruktor.

    fallschritt schrieb:

    TyRoXx schrieb:

    Wenn du es unbedingt brauchst, kannst du auch deinen eigenen String schreiben, der dieselbe Schnittstelle wie std::string implementiert.

    Viel Spass beim Implementieren von >100 Memberfunktionen.

    TyRoXx schrieb:

    Kein Problem und völlig normal in C++.

    Habe auch das Gefühl, dass C++ sehr viel Boilerplate-Code bedeutet.

    Du hast mit std::string angefangen. Heute würde man den nicht mehr so entwerfen.

    fallschritt schrieb:

    TyRoXx schrieb:

    Exceptions baut man in C ständig mit if nach.

    Exceptions setzt man auch in C++ extrem spärlich ein. Meiner Erfahrung nach kann man problemlos drauf verzichten.

    Nein, kann man nicht. Das Ergebnis ist immer Müll. Jede Funktion gibt am Ende false , -1 oder nullptr im Fehlerfall zurück. Die eigentlichen Ergebnisse landen in irgendwelchen Membern von Gottklassen. Die Fehlerursachen werden meist als Alibi in überfüllte Log-Dateien geschrieben.

    fallschritt schrieb:

    Bisschen mehr assert, bei den wenigen verbleibenden Fällen macht man halt ein if, aber das hätte man in C++ genauso gemacht, weil erwarteter Fehler.

    assert ist orthogonal zu throw . Die haben nichts miteinander zu tun. Am Anfang fand man Ideen wie std::out_of_range akzeptabel, aber das ist lange vorbei.
    if zur Behandlung von Fehlern ist Zeitverschwendung. Dafür hat man die Exception erfunden.
    Ich sehe zwei sinnvolle Exception-Typen: bad_alloc und system_error . bad_alloc wirft man nie selbst. system_error werfen Bibliotheken, die C-Schnittstellen kapseln.
    Man sollte ansonsten noch davon ausgehen, dass fremder Code andere Exceptions werfen kann.
    Ein sauberes, modernes C++-Programm hat in der Regel ein try und ein catch . Jedes weitere sollte gut überlegt sein.
    Ein sauberes, modernes C-Programm hat unzählige if s, die fast immer nichts tun. Der Code muss geschrieben, gepflegt, korrigiert, getestet und ignoriert werden. Deswegen sind Exceptions besser.

    fallschritt schrieb:

    Bei fehlgeschlagenem malloc schreib ich mir ein Handler, da prüfe ich nicht jeden Aufruf.

    Und was kann der Handler dann machen außer den Prozess zu beenden? Genau das würde bad_alloc auch standardmäßig tun.



  • TyRoXx schrieb:

    fallschritt schrieb:

    Aber predigt man in C++ nicht, dass Konstruktoren viel Logik enthalten können? Eine std::list z.B. macht im Default-Konstruktor Memory-Allokationen, damit gehen deine Hacks nicht.

    Eigentlich predigt man, dass Konstruktoren gar keine Logik enthalten sollen, sondern höchstens eine Initialisierungsliste, die nur initialisiert.
    std::list sollte man generell nicht verwenden.

    Der Konstruktor muss alle Invarianten herstellen. Invarianten sind gut. Wenn ein Objekt damit man es verwenden kann immer eigenen Speicher braucht, dann sollte es eine Invariante "besitzt immer Speicher" haben, und diese muss im Konstruktor dann hergestellt werden. D.h. der Konstruktor muss Speicher anfordern.
    Oder ein File oder eine Datenbank-Verbindung, Transaktion - was auch immer aufmachen/erzeugen/...

    Natürlich kann man das alles in Form einer Initialisierungsliste schreiben - was ich i.A. auch für gut halte (zumindest so lange es keine übertrieben umständlichn Kunstgriffe/Hilfskonstrukte erfordert). Nur darum geht's "fallschritt" ja nicht. Es geht ihm darum dass der Konstruktor mehr macht als nur ein paar Werte mit Konstanten zu initialisieren. Bzw. um alles was dazu führt dass ein Objekt nicht mehr "memcpy-kopierbar" ist.

    Und solche Fälle hast du bei RAII *dauernd*. Weil es das ist was RAII ausmacht.

    D.h. wörtlich genommen stimmt das schon was du schreibst, hat dann aber mit der Aussage von "fallschritt" nichts zu tun. Oder, wenn man es so interpretiert dass es ein Bezug zur Aussage von "fallschritt" entsteht, dann stimmt was du schreibst überhaupt nicht. Weil es dann gleichbedeutend wäre mit "man predigt kein RAII zu verwenden".



  • hustbaer schrieb:

    Wenn ein Objekt damit man es verwenden kann immer eigenen Speicher braucht, dann sollte es eine Invariante "besitzt immer Speicher" haben, und diese muss im Konstruktor dann hergestellt werden. D.h. der Konstruktor muss Speicher anfordern.

    Falsch, der Konstruktor bekommt einen Parameter für den Speicher, den der Aufrufer zu besorgen hat.

    EDIT: Das gilt natürlich eher für High-Level-Code. Konstruktoren auf der niedrigsten Ebene wie std::vector<T>::vector(InputIterator, InputIterator) dürfen Speicher anfordern, weil es ihre einzige Aufgabe ist. Man sieht aber am Uniform-Initialization-Desaster, dass namenlose Konstruktoren selbst für Experten schwer zu beherrschen sind. Vielleicht wäre std::make_vector sinnvoller gewesen.

    Die Konstruktoren hätten am besten so ausgesehen:

    vector();
    vector(vector const &);
    vector(vector &&);
    template <class InputIterator>
    vector(InputIterator, InputIterator, Alloc);
    
    //bzw.
    template <class InputRange>
    explicit vector(InputRange, Alloc);
    

    Alle anderen kann man mit freien Funktionen nachbauen.

    template <class T>
    some-range-type<T> n_times(T const &, std::size_t);
    
    template <class T, class Alloc>
    std::vector<T> make_vector(std::initializer_list<T>, Alloc);
    

    hustbaer schrieb:

    Oder ein File oder eine Datenbank-Verbindung, Transaktion - was auch immer aufmachen/erzeugen/...

    Genau das gehört eben nicht in Konstruktoren.

    //schlecht, weil
    // - der Konstruktor keinen eigenen Namen hat
    // - man höllisch mit Exceptions aufpassen muss
    // - die Öffnen-Operation ohne jeden Grund untrennbar mit dem Wrapper um ein einfaches Handle verbunden ist (zwei orthogonale Aufgaben in einer Klasse)
    file::file(boost::filesystem::path const &path);
    
    //besser
    file::file(implementation-defined-handle) noexcept;
    file open(boost::filesystem::path const &path);
    


  • fallschritt schrieb:

    Zu einen kennst Du Dich recht wenig aus.
    Zum anderen solltest Du Dir überlegen, ob Du hier richtig bist, wenn Du nur C++-bashen willst.


Anmelden zum Antworten