Wieso gibt es keine gute Programmiersprache?



  • Finnegan schrieb:

    mach_was() , mach_noch_mehr() und und_noch_mehr() sind wohl unabhängig vom Objekt, da man sie auch aufrufen kann,
    wenn das Objekt nicht existiert (=nicht initialisiert wurde).

    Das war schnell dahingetippter Beispielcode. In der Realität habe ich foo womöglich drei verschiedene Objekte übergeben (Hauptobjekt, Anzahl der Elemente, und Puffer oder so was ähnliches), und die übergebe ich dann auch den Unterfunktionen.

    Finnegan schrieb:

    Falls doch eine Abhängigkeit vom Objekt besteht, ist tatächlich manchmal redundanter Code die einfachste Lösung

    Danke für die Bestätigung, dass ich in solchen Fällen schlechter programmieren muss. Ich bleibe bei C, da habe ich mehr Kontrolle über alles und muss den Quellcode nicht runterziehen.

    Finnegan schrieb:

    Für die wenigen Sonderfälle, wo sich das nicht elegant auflösen lässt, hilft entweder eine zusätzliche Status-Variable, oder man erstellt das Objekt zur Not eben auf dem Heap mit explizitem delete / unique_ptr<>.reset() oder verwendet meine oben vorgeschlagene Stack- new -Variante.
    Ich glaube diese Fälle sind allerdings derart selten, dass sie nicht wirklich als überzeugendes Argument gegen Konstruktoren/Destruktoren taugen.

    Und deswegen hätte ich nur einfach gerne Templates in C, und den ganzen anderen Kram könnt ihr behalten. Deal? 🙂

    Finnegan schrieb:

    Virtuellen Speicher verwalten klingt schon sehr low-level. In solchen Fällen würde ich wahrscheinlich auch auf ein simples struct mit einer expliziten
    Initialisierungsfunktion zurückgreifen, oder nur sehr leichtgewichtige Klassen entwerfen.

    Sag an, genau das ist ja der Fall. Und trotzdem habe ich beim Leichtgewicht noch ein paar Kernel-Calls. Was aber immer noch besser als der Standard ist, was auf Windows bedeutet, sich den Cache und möglich auch den TLB zu ruinieren, weil man jetzt Daten von A nach B kopieren muss, weil der alte Speicher nicht ausreicht.

    (Und auf den TLB kann ich schon keine Rücksicht mehr nehmen, weil Windows im Gegensatz zu Linux die Infrastruktur verkackt hat - aber das ist ein anderes Thema).

    Finnegan schrieb:

    Für solche Spezialfälle hindert einen C++ übrigens nicht daran eine Klasse ohne expliziten Konstruktor/Destruktor zu
    schreiben (=default) und es genau so zu handhaben wie du es in C machen würdest.

    Wird ein leerer Konstruktoraufruf wegoptimiert?



  • dachschaden schrieb:

    Wird ein leerer Konstruktoraufruf wegoptimiert?

    Das macht wohl noch der schlechteste C++-Compiler.



  • Bin ich der einzige, der sich fragt, ob jemand der Diskussionsteilnehmer tatsächlich C++ in der Arbeit für ein großes Projekt verwendet?



  • Finnegan schrieb:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.

    Ja, ich glaube es gibt kaum etwas, das in dieser wahnwitzigen Sprache nicht geht:

    #include <iostream>
    #include <type_traits>
    
    struct Objekt
    {
    	Objekt(int value) : value{ value } {}
    	void print() const { std::cout << value << std::endl; }
    	int value;
    };
    
    auto main() -> int
    {
    	// Reserviere Speicher für Objekt auf Stack.
    	typename std::aligned_storage<sizeof(Objekt), alignof(Objekt)>::type objekt_auf_stack;
    	// Erstelle Objekt.
    	auto& objekt = *(new (&objekt_auf_stack) Objekt{ 5 });
    	// Verwende Objekt.
    	objekt.print();
    	// Zerstöre Objekt.
    	objekt.~Objekt();
    }
    

    Versus:

    #include <iostream>
    
    struct Objekt
    {
    	Objekt(int value) : value{ value } {}
    	void print() const { std::cout << value << std::endl; }
    	int value;
    };
    
    int main()
    {
    	Objekt obj(5);
    	obj.print();
    	return 0;
    }
    

    No other comment included!



  • 5cript schrieb:

    hustbaer schrieb:

    5cript schrieb:

    invarianzfreie Programmierung

    Nie gehört. Link!

    Ich meinte "keine Invarianten". Invarianten oder "stille Gegebenheiten" salopp ausgedrückt sind Fehlerquellen, die Kapselung benötigen.

    Entweder musst du mich für viel blöder halten als ich bin, oder dich für viel schlauer als du bist.
    Ich weiss schon was Invarianten sind. Vielleicht solltest du dagegen mal lieber keine Begriffe verwenden die es nicht gibt/keiner sonst verwendet.

    5cript schrieb:

    Wenn man sowas vermeiden kann, kann man auch keine Kapselungsfehler machen oder Sachen vergessen.

    Natürlich kann man dann noch Kapseln. Und natürlich kann man dann noch Dinge vergessen. Manchmal schreibst du schon phenomänal unsinnigen Unsinn.

    5cript schrieb:

    EDIT: OOP ist Modellierung mit State. Der Versuch state zu bändigen. Aber das kann man auch anders lösen.

    Ja klar. Man kann alles immer irgendwie anders machen. Man kann z.B. jedes Programm auch in Assembler schreiben. Ist nur meistens net so spassig.



  • @dachschaden
    Wenn du keine Exceptions verwenden willst, dann verwende keine. Du kannst Exception Handling sogar per Compiler-Switch abdrehen.
    Und was Konstruktoren/Destruktoren angeht: Hallo, Inlining?

    Natürlich ist es trotzdem in den meisten Fällen beknackt so zu programmieren. Das Argument "C++ zwingt mir das auf" ist aber - davon unabhängig - meistens falsch.



  • dachschaden schrieb:

    Danke für die Bestätigung, dass ich in solchen Fällen schlechter programmieren muss. Ich bleibe bei C, da habe ich mehr Kontrolle über alles und muss den Quellcode nicht runterziehen.

    dachschaden schrieb:

    Und deswegen hätte ich nur einfach gerne Templates in C, und den ganzen anderen Kram könnt ihr behalten. Deal? 🙂

    Am Ende steht und fällt die ganze Argumentation damit, ob man es im Zweifelsfall genau so machen kann wie in C.
    Selbstverständlich kann man das, wenn man tatsächlich einen solchen, meiner Einschätzung nach extrem selten Sonderfall hat, der sich anders nicht elegant umformulieren lässt.

    Finnegan schrieb:

    Wird ein leerer Konstruktoraufruf wegoptimiert?

    Wird in C ein Aufruf wegoptimiert, bei dem zur Compile-Zeit bekannt ist, dass es sich um eine leere Funktion handelt?
    Wenn du tatsächlich solchen low-level Optimierungskram machst, solltest du das eigentlich wissen.

    dachschaden schrieb:

    Sag an, genau das ist ja der Fall. Und trotzdem habe ich beim Leichtgewicht noch ein paar Kernel-Calls. Was aber immer noch besser als der Standard ist, was auf Windows bedeutet, sich den Cache und möglich auch den TLB zu ruinieren, weil man jetzt Daten von A nach B kopieren muss, weil der alte Speicher nicht ausreicht.

    Na wer hat denn die Kernel-Calls in den Konstruktor geschrieben wenn nicht du? Der Compiler jedenfalls nicht.
    Wenn du das vermeiden willst, kannst du z.B. den virtuellen Speicher erst dann allozieren, wenn zum ersten mal darauf zugegriffen wird
    (z.B. in einer get() -Methode, wenn hinter dem internen Pointer noch kein Speicher steckt). Am Ende bestimmt immer noch der Programmierer was passiert.
    Oder du wendest eine der vielen genannten alternativen Methoden an, bis hin zu klassischem C-Style.

    Finnegan



  • Zeus schrieb:

    ... Versus: ...

    No other comment included!

    Die Anforderung war, dass zwar auf dem Stack immer Speicher für das Objekt reserviert werden soll, der Programmierer aber bestimmen möchte ob und wann es konstruiert und zerstört wird.
    Die zweite Variante erfüllt diese Anforderung nicht, da Reservierung von Stack-Speicher und Konstruktoraufruf nicht getrennt sind.

    Ferner war der Code lediglich ein Beispiel dafür wie man das für beliebige Klassen in C++ umsetzen kann und mitnichten eine Anleitung wie man immer und überall Objekte kostruieren sollte (Bloss nicht!).

    Finnegan



  • Nehmt mal diesen "Dachschaden" nicht so ernst. Der Typ ist ein Nazi. Bei solchen Leuten fehlen immer ein paar Latten am Zaun.



  • "Dachschaden" ist halt psychisch krank.



  • hustbaer schrieb:

    5cript schrieb:

    Wenn man sowas vermeiden kann, kann man auch keine Kapselungsfehler machen oder Sachen vergessen.

    Natürlich kann man dann noch Kapseln. Und natürlich kann man dann noch Dinge vergessen. Manchmal schreibst du schon phenomänal unsinnigen Unsinn.

    *weniger -> fixed
    &ja den Begriff verwendet niemand, war mir so aus dem Kopf gerutscht.

    Ich kann schließlich nicht alles aufzählen, wofür Kapselung gut ist 🙄

    Hey ich benutze auch manchmal friend um Methoden private zu machen.
    come kill me!



  • ich weiß echt nicht schrieb:

    "Dachschaden" ist halt psychisch krank.

    Er berichtete bereits von einer gescheiterten Kindheit. Ich entlockte ihm diesentsprechende Statements. Armes Schwein. Möget ihr seine fachlichen Äußerungen vor dem eben genannten Hintergrund betrachten, ergo: mit Vorsicht genießen. Ich nehme an, dass seine Erkrankung sein Urteilsvermögen trübt.



  • Finnegan schrieb:

    Zeus schrieb:

    ... Versus: ...

    No other comment included!

    Die Anforderung war, dass zwar auf dem Stack immer Speicher für das Objekt reserviert werden soll, der Programmierer aber bestimmen möchte ob und wann es konstruiert und zerstört wird.
    Die zweite Variante erfüllt diese Anforderung nicht, da Reservierung von Stack-Speicher und Konstruktoraufruf nicht getrennt sind.

    Ferner war der Code lediglich ein Beispiel dafür wie man das für beliebige Klassen in C++ umsetzen kann und mitnichten eine Anleitung wie man immer und überall Objekte kostruieren sollte (Bloss nicht!).

    Finnegan

    Vielleicht sollte nach den Sinn deines Beispiel fragen?



  • Zeus schrieb:

    Vielleicht sollte nach den Sinn deines Beispiel fragen?

    Vielleicht solltest du lesen, was du zitiert hast?

    Finnegan schrieb:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.



  • Wird ja immer schlimmer.. schrieb:

    Zeus schrieb:

    Vielleicht sollte nach den Sinn deines Beispiel fragen?

    Vielleicht solltest du lesen, was du zitiert hast?

    Finnegan schrieb:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.

    Vielleicht solltest du mehr effektive C++ Bücher lesen, damit man weißt dass es Unsinn ist. Statt zu sagen, dass es Unsinn ist, wird sehr unsinniger Code gepostet.



  • Andromeda schrieb:

    Er berichtete bereits von einer gescheiterten Kindheit. ...

    "Ad hominem" zu argumentieren kommt zumindest bei mir nicht besonders gut an, ungeachtet dessen wie stark oder schwach die Argumente des anderen sind.
    Wenn du nichts substantielles zur fachlichen Diskussion beizutragen hast, wäre zumindest ich dankbar, wenn du in Zukunft einfach schweigen würdest.

    Finnegan



  • Finnegan schrieb:

    Andromeda schrieb:

    Er berichtete bereits von einer gescheiterten Kindheit. ...

    "Ad hominem" zu argumentieren kommt zumindest bei mir nicht besonders gut an,

    Du hast natürlich Recht. Ad hominem ist niemals eine gültige Argumentationsfigur. Ich gebe zu, dass es mir in dem Fall nur darum ging, diesen Freak zu dissen und zu bashen. Ich mag nunmal keine Nazis. Bei Nazis geht mir das Messer in der Tasche auf. Egal, wo sie in Erscheinung treten.

    Btw, ich bin selber kein Freund von C++. Mir ist C auch viel sympathischer. Aber letztlich beruht das alles auf Erfahrungswerten. Wer mit anspruchsvollen Softwareprojekten auf leistungschwacher Hardware zu tun hatte (aus Kostengründen), und andererseits unter Zeitdruck Programme hinfrickeln durfte, die früh serienreif sein sollten und denen man nicht anmerken sollte, dass sie mit der heißen Nadel gestrickt waren, der wird mit C++ in keinem Fall glücklich.

    Ich bin der Meinung, dass C++ im mittleren Leistungsegment durchaus seine Berechtigung hat. Aber sobald ein managed environment aka .NET, Java-VM, Docker, usw. vorhanden ist, hat C++ ausgedient.



  • Zeus schrieb:

    #include <iostream>
    
    struct Objekt
    {
    	Objekt(int value) : value{ value } {}
    	void print() const { std::cout << value << std::endl; }
    	int value;
    };
    
    int main()
    {
    	Objekt obj(5);
    	obj.print();
    	return 0;
    }
    

    No other comment included!

    Bitte lies nochmal:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.

    Dein Code hingegen macht genau das nicht. Er zwingt mich, meinen Init-Code in eine eigene Funktion zu packen, oder halt mit der unter Umständen teuren Objektinitialisierung zu leben.

    hustbaer schrieb:

    Wenn du keine Exceptions verwenden willst, dann verwende keine.

    Bitte lies dir das nächste Mal Posts genauer durch:

    dachschaden schrieb:

    Für ersteres kann ich auch einfach irgendwelchen anderen C-Libs verwenden, die keine Exceptions kennen, und auch selbst keine schreiben

    hustbaer schrieb:

    Und was Konstruktoren/Destruktoren angeht: Hallo, Inlining?

    Finnegan schrieb:

    Wird in C ein Aufruf wegoptimiert, bei dem zur Compile-Zeit bekannt ist, dass es sich um eine leere Funktion handelt?

    Dann ist modulübergreifende LTO für, sagen wir den g++, endlich soweit, dass ein memset , welches einen Speicherbereich nullen soll (private Daten, bei denen sichergestellt werden soll, dass diese nicht noch im Speicher rumgeistern, falls der Server geowned wird), nicht wegoptimiert wird, aber andere, komplett leere Funktionsaufrufe schon? Genau das war nämlich das Problem bei Heartbleed - dass die Daten so schön weit beisammen im Speicher waren, weil OpenSSL seinen eigenen Allokator bebaut hat, aber nicht hinter sich hergeräumt hat (wobei ich nicht mal davon ausgehe, dass sie memset verwendet haben - nur hätte ihnen das wohl auch nicht viel gebracht).

    LTO wirft sowas weg für lokale Variablen - Dead Store Elimination. Und nicht nur bei lokalen Variablen, sondern auch für Zeiger, die danach freigegeben werden ( free/delete ). Ohne LTO kann der Linker (bei Funktionen, bei denen die Implementierung in einem anderen Modul liegt) nicht sagen, ob der Call eingespart werden kann. Zumindest ist das bei C der Fall. Und meine Frage war jetzt, ob in Fällen, in denen ich Schnittstelle und Implementierung trenne, der Linker intelligent genug ist, das zu erkennen.

    Im eigenen Modul - ja klar, das erkennt der Compiler. In anderen Modulen? Und genau das ist meine Frage.

    hustbaer schrieb:

    Natürlich ist es trotzdem in den meisten Fällen beknackt so zu programmieren.

    Meine Rede:

    dachschaden schrieb:

    kann man machen, aber dann schaut jeder einen an wie einen Geistesgestörten.

    Finnegan schrieb:

    Wenn du das vermeiden willst, kannst du z.B. den virtuellen Speicher erst dann allozieren, wenn zum ersten mal darauf zugegriffen wird
    (z.B. in einer get() -Methode, wenn hinter dem internen Pointer noch kein Speicher steckt).

    Dazu müsste ich hinbekommen, dass existierender Code (sagen wir mal spontan, pthreads, oder entsprechende Implementierung in C++) diesen get() auch aufruft. Wird er wahrscheinlich nicht machen. Deswegen muss ich, bevor ich meinen Speicher übergebe, erst get() aufrufen. Jetzt benenne get() in _init um, weil es effektiv genau das ist, und wir sind wieder beim unnötigen Funktionsaufruf.

    Andromeda schrieb:

    Nehmt mal diesen "Dachschaden" nicht so ernst. Der Typ ist ein Nazi. Bei solchen Leuten fehlen immer ein paar Latten am Zaun.

    Jetzt geht er in die Vollen ...

    Finnegan schrieb:

    P.S.: Und was zum Henker geht hier in diesem Thread? "Nazi"? "psychisch krank"?
    Ist das ein Diskussionsniveau das wir hier in einem technischen Forum haben wollen? (Denke da kann man noch einiges mehr löschen!)

    Er ist ein Troll, der verzweifelt darum bemüht ist, Aufmerksamkeit zu erheischen. Wie mein Urgroßvater zu sagen pflegte: "Garnnich drum kümmern".

    EDIT: LTO-Paragraph korrigiert (unschönen, offenen Satz vervollständigt), Storage => Store, und hinzugefügt, dass dem auch bei Zeigern auf dem Heap so ist, wenn diese freigegeben werden.



  • dachschaden schrieb:

    Zeus schrieb:

    #include <iostream>
    
    struct Objekt
    {
    	Objekt(int value) : value{ value } {}
    	void print() const { std::cout << value << std::endl; }
    	int value;
    };
    
    int main()
    {
    	Objekt obj(5);
    	obj.print();
    	return 0;
    }
    

    No other comment included!

    Bitte lies nochmal:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.

    Dein Code hingegen macht genau das nicht. Er zwingt mich, meinen Init-Code in eine eigene Funktion zu packen, oder halt mit der unter Umständen teuren Objektinitialisierung zu leben.

    Objektinitialisierung werden erst teuer, wenn Leute nicht wissen, wo die Kosten entstehen. Und bei dir hab ich den Eindrück, dass das so ist, weil viele Probleme entstehen wenn man Objekt-Initialisierung und -Konstruktion trennt. Sonst empfehle ich die Buchreihe zu lesen, die ich hier schon mal erwähnt hatte.



  • Zeus schrieb:

    dachschaden schrieb:

    Zeus schrieb:

    #include <iostream>
    
    struct Objekt
    {
    	Objekt(int value) : value{ value } {}
    	void print() const { std::cout << value << std::endl; }
    	int value;
    };
    
    int main()
    {
    	Objekt obj(5);
    	obj.print();
    	return 0;
    }
    

    No other comment included!

    Bitte lies nochmal:

    dachschaden schrieb:

    Kann ich in C++ dem Compiler sagen, dass er nur ein bisschen Speicherbereich auf dem Stack reservieren soll für ein Objekt, und Initialisierung und Freigabe komplett mir überlassen soll? Wenn ja, will ich nichts gesagt haben.

    Dein Code hingegen macht genau das nicht. Er zwingt mich, meinen Init-Code in eine eigene Funktion zu packen, oder halt mit der unter Umständen teuren Objektinitialisierung zu leben.

    Objektinitialisierung werden erst teuer, wenn Leute nicht wissen, wo die Kosten entstehen. Und bei dir hab ich den Eindrück, dass das so ist, weil viele Probleme entstehen wenn man Objekt-Initialisierung und -Konstruktion trennt. Sonst empfehle ich die Buchreihe zu lesen, die ich hier schon mal erwähnt hatte.


Anmelden zum Antworten