Wer räumt eigentlich den Speicher auf ;-)
-
xaoC schrieb:
Der Grund warum prinzipiell nicht per Value übergeben wird, ist doch der, sich anfallende Kosten für überflüssige Objekterstellung zu sparen
Ja, aber auch nur, wenn das Objekt viel Daten enthält oder der ctor bzw. dtor nicht trivial ist.
xaoC schrieb:
Prinzipiell sei anzumerken, dass es überall gelehrt wird, per Referenz oder Zeiger zu übergeben, ob es von der Objektlebenszeit her sinnvoll ist oder nicht.
Und wo soll sowas gelehrt werden? Bestimmt nicht von erfahrenen C++ Leuten. By-value zu übergeben, ist jedenfalls erstmal default. Nur wenn das zu teuer wird oder aufgrund von Polymorphie nicht möglich ist, übergibt man by-reference. Und bedenke, du übergibst in deinem Beispiel Zeiger. Also rein technisch gesehen by-value.

xaoC schrieb:
Zielorientiert ist richtig, aber ich hätte trotzdem gerne deine Begründungen für Abweichungen von der meiner Meinung nach eher vorherrschenden Zeiger/Referenzübergabe gehört. Übergabe per Value sieht man nämlich fast nirgends, egal wie popelig das Beispiel.
Ach ja? Wollen wir mal schnell den Standard durchgehen und jede Funktion anschauen, wo man fast nie by-value Übergabe sieht? Und auch ausserhalb des Standards wird das nicht viel anders aussehen. Keine Ahnung wovon du sprichst, aber mit der Realität hat das nicht viel zu tun, denn by-value verwendet man schon recht häufig.
Zu deinem Problem:
ich würde der Klasse ehrlich gesagt zwei normale string Objekte spendieren. Das wird wohl auch der gängiste Weg sein. Und über das Speichermanagement brauchst du dir dann auch keine Gedanken machen. Ansonsten, wenn du die Zeiger beibehalten willst, dann solltest du dir evtl. wirklich mal shared Pointer anschauen.
Ach, und nochwas, std::string's dynamisch anzulegen ist so sinnvoll wie 'ne Badehose am Nordpol. Das ist praktisch doppelte Speicherreservierung und vollkommen unnötig. Somit ein weiteres Argument gegen deine bisherige Vorgehensweise und ebenfalls gegen eine Verwendung von Smart-Pointern an dieser Stelle, da man ja dann auf dynamisch erzeugte Objekte angewiesen ist. Insofern ist ein std::string Objekt ja schon dein "Array Smart-Pointer". Mir ist zwar immer noch nicht ganz klar, auf was du hinaus willst, aber evtl. suchst du ja sowas wie eine COW String Implementation.
-
xaoC schrieb:
joomoo schrieb:
Warum nicht boost? Da gibt's nähmlich boost::scoped_array und boost::shared_array. Und warum die nicht nehmen? So auf Geschwindigkeit ist dein programm sicher nicht aus oder?
mfg.
Weil man Boost auch wieder erst lernen muss. Ich frage mich ernsthaft, wann man in C++ anfangen kann, sich mit dem Programm zu beschäftigen anstatt mit der Sprache. Inwieweit ersetzt Boost denn die STL? Komplett oder ist das eher ergänzend? Ansonsten würde ich wohl eher auf Smartpointer und Boost verzichten und lieber solides Mittelalter lernen ...
In der nächsten C++ Version sind die shared_ptr aus der Boost Teil der STL. Kann man sich im TR1 anschauen. (Tr steht für "Technical Report in Standart Library Extensions")
Ansonsten kann ich für mich behaupten, dass ich keinen Speicher freigebe! Ich lasse den Speicher freigeben (von meinen Smart-Pointern). Damit bin ich sicher, dass ich keine Speicherleaks erzeuge. (von wenigen Ausnahmen abgesehen.)
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
Sven
-
groovemaster schrieb:
Ja, aber auch nur, wenn das Objekt viel Daten enthält oder der ctor bzw. dtor nicht trivial ist.
Das ist einleuchtend und bedarf wohl auch keiner Diskussion.
groovemaster schrieb:
Und wo soll sowas gelehrt werden? Bestimmt nicht von erfahrenen C++ Leuten.
Ich will jetzt nicht nachschlagen, aber ich schätze in ca. 80% der Lehrbücher.
Schulen lehren es übrigens genauso. Jedenfalls ist der Eindruck der entsteht, ganz klar: "Nutzt Zeiger/Referenzen etc., ist besser, schneller etc.".groovemaster schrieb:
By-value zu übergeben, ist jedenfalls erstmal default. Nur wenn das zu teuer wird oder aufgrund von Polymorphie nicht möglich ist, übergibt man by-reference. Und bedenke, du übergibst in deinem Beispiel Zeiger. Also rein technisch gesehen by-value.

By-Value ist Default, ja, da weiß ich auch.
Mit geht's auch nicht darum, Zeigerübergabe als Standard zu propagieren oder für irgendetwas Werbung zu machen, sondern herauszufinden, wie eure
Vorgehensweise da aussieht.groovemaster schrieb:
Ach ja? Wollen wir mal schnell den Standard durchgehen und jede Funktion anschauen, wo man fast nie by-value Übergabe sieht?
Nein, will ich nicht. Weil es nicht das ist, was ich bis jetzt gesehen habe. Grundtypen wie int oder float als Parameter by value zu übergeben ist gängig, bei Objekten sieht das IMO ganz anders aus.
Mit stellte sich die Sinnfrage nach solchen Konstrukten wie ich im ersten Post angegeben habe. Und die Übergabe per value scheint hier nur logisch. Aber da muss man doch mal drüber reden können.groovemaster schrieb:
Und auch ausserhalb des Standards wird das nicht viel anders aussehen. Keine Ahnung wovon du sprichst, aber mit der Realität hat das nicht viel zu tun, denn by-value verwendet man schon recht häufig.
s.o.
groovemaster schrieb:
Zu deinem Problem:
ich würde der Klasse ehrlich gesagt zwei normale string Objekte spendieren. Das wird wohl auch der gängiste Weg sein. Und über das Speichermanagement brauchst du dir dann auch keine Gedanken machen.Ack.
groovemaster schrieb:
Ansonsten, wenn du die Zeiger beibehalten willst, dann solltest du dir evtl. wirklich mal shared Pointer anschauen.
kk.
groovemaster schrieb:
Ach, und nochwas, std::string's dynamisch anzulegen ist so sinnvoll wie 'ne Badehose am Nordpol. Das ist praktisch doppelte Speicherreservierung und vollkommen unnötig.
Für mich ist ein std::string erst mal ein Objekt wie jedes andere auch. Wenn ich dieses auf dem Heap anlegen will mache ich ein new. Ich weiss nicht was
da jetzt doppelt reserviert werden soll?groovemaster schrieb:
Mir ist zwar immer noch nicht ganz klar, auf was du hinaus willst, [...].
Es geht mir im Grunde darum, inwieweit Übergaben NICHT als value in solchen Fällen wie oben Sinn machen, wenn nicht, warum und was Alternativen dazu wären.
Das Fazit, was ich aus dieser Diskussion hier mitnehme, ist im Prinzip:
- Nutze SmartPointer wenn möglich
- by value in diesem Falle sinnvollWas definitiv so in meiner Gegenwart im Grunde nirgends vermittelt wurde (allgemein gemünzt):
Mehr die Vorgehensweise als die Technik zu beachten. Denn no-by value ist IMO für komplexere Objekte als Grundtypen eher Standard in Literatur als by value. Meine Meinung. Das das keinen Sinn macht, wenn man den Kontext nicht betrachtet, ist mir dann auch klar, aber wie IHR den Kontext seht, hat mich interessiert.
-
Für mich ist ein std::string erst mal ein Objekt wie jedes andere auch. Wenn ich dieses auf dem Heap anlegen will mache ich ein new. Ich weiss nicht was
da jetzt doppelt reserviert werden soll?Die Frage lautet: WOZU willst du es auf dem Heap anlegen? Das würde nur bei C-Strings einen Sinn ergeben. Und Falls du mehrere String-Objekte brauchst dann nimm std::vector und nicht new[].
mfg.
-
sven_jo schrieb:
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
SvenDas sind keine SmartPtr sonder ein dynamisches Array und ein String, die verwalten zwar intern auch den benötigten Speicher aber SmartPtr sind etwas anderes.
-
xaoC @ Work schrieb:
Ich will jetzt nicht nachschlagen, aber ich schätze in ca. 80% der Lehrbücher.
Schulen lehren es übrigens genauso. Jedenfalls ist der Eindruck der entsteht, ganz klar: "Nutzt Zeiger/Referenzen etc., ist besser, schneller etc.".Ok, ist schon etwas länger her, dass ich ein C++ Lehrbuch in den Händen hatte. Aber ich hoffe, du hast das nicht falsch verstanden. By-reference darf nicht Ziel der Parameterübergabe sein, es ist einfach ein zweckgebundenes sprachunabhängiges Mittel.
xaoC @ Work schrieb:
Für mich ist ein std::string erst mal ein Objekt wie jedes andere auch. Wenn ich dieses auf dem Heap anlegen will mache ich ein new. Ich weiss nicht was
da jetzt doppelt reserviert werden soll?Du bemühst den Speichermanager, die paar Bytes die std::string für seine Member benötigt, zu reservieren. Intern bemüht std::string wieder den Speichermanager (bzw. verwendeten Allokator), um Speicher für den Inhalt der Zeichenkette zu reservieren. Das ist ungefähr so absurd, wie einen Smart-Pointer dynamisch zu reservieren (ok, leicht übertrieben). Aber um das mal mit dem Thema zu verbinden, die sinnvolle Verwendung von automatischem und dynamischem Speicher erfordert letztendlich genauso viel Fingerspitzengefühl, wie die Parameterübergabe by-value oder by-reference.
xaoC @ Work schrieb:
- Nutze SmartPointer wenn möglich
Smart-Pointer aber nur, wenn man keinen passenden Container parat hat und einem der evtl. Overhead egal ist. Ich würde es deshalb eher wie folgt formulieren:
Nutze Smart-Pointer wenn möglich anstatt roher Zeiger.
xaoC @ Work schrieb:
Mehr die Vorgehensweise als die Technik zu beachten. Denn no-by value ist IMO für komplexere Objekte als Grundtypen eher Standard in Literatur als by value.
Was ja auch vollkommen ok ist. Nur man sollte halt nicht stur eine Vorgehensweise durchziehen, sondern die gebotenen Sprachmittel diesbzgl. sinnvoll einsetzen.
-
xaoC schrieb:
Weil man Boost auch wieder erst lernen muss. Ich frage mich ernsthaft, wann man in C++ anfangen kann, sich mit dem Programm zu beschäftigen anstatt mit der Sprache.
Boost gehört nicht zur Sprache, genauso wie die STL im eigentlichen Sinne. Sie gehört zwar zum Standard, ist aber nicht fest integriert sondern eben eine Bibliothek, ergo beschäftigst du dich nicht mit der Sprache, wenn du dich mit der STL beschäftigst. (Sie wurde auch zu erst nicht in C++ sondern in Ada implementiert!)
xaoC schrieb:
Inwieweit ersetzt Boost denn die STL? Komplett oder ist das eher ergänzend?
Sie ergänzt und erweitert/verbessert in einigen Bereichen (z.B. Iteratoren)
Zur laufenden Diskussion:
Kommt es nicht auch ein wenig darauf an, wie man by-(value|reference) definiert? Aus implementierungsunabhängiger Sicht ist doch eine const Referenz eigentlich auch eine by-value Übergabe (schließlich wird der übergebene Wert nicht verändert). Auch die Regel für die Übergabe von Objekten kann man sprachunabhängig auf die Fälle "Verändern" und "Nicht verändern" bringen, für beide gibt es je nach Parametertyp klare Vorgehensweisen.
Außerdem möchte ich noch anmerken, dass Zeiger als Parameter selten sinnvoll sind, zumindest wenn es sich um eine normale Objektübergabe handelt. Schließlich benutzt man Zeiger in C++ nur, wenn es sich um veränderlichen (Adressbezogen) oder auf dem Heap zu alloziierenden Speicher handelt, ansonsten reichen Referenzen. Auch für Smartpointer fiele mir jetzt kein sinnvolles Szenario ein.
Also, wo ist das Problem?
-
Konrad schrieb:
sven_jo schrieb:
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
SvenDas sind keine SmartPtr sonder ein dynamisches Array und ein String, die verwalten zwar intern auch den benötigten Speicher aber SmartPtr sind etwas anderes.
Vollkommen korrekt! Da C++ Klassen für dynamische Arrays und Strings besitzt, braucht man keine Smart-Ptr für Felder. Daher meine Aussage: Die Smart-Pointer für Felder heißen std::vector und std::string.
Die Smart-Pointer boost::scoped_array und boost::shared_array könnten zum migrieren von altem Code verwendet werden. Diese Vorgehensweise kann ich nicht empfehlen.
Wenn man in seinem Code ein new[...] / delete ...[] verwendet, sollte man den Code auf echte C++-Klassen für dynamische Felder oder Strings umstellen. -> also: std::vector und std::string.
Sven
-
sven_jo schrieb:
Konrad schrieb:
sven_jo schrieb:
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
SvenDas sind keine SmartPtr sonder ein dynamisches Array und ein String, die verwalten zwar intern auch den benötigten Speicher aber SmartPtr sind etwas anderes.
Vollkommen korrekt! Da C++ Klassen für dynamische Arrays und Strings besitzt, braucht man keine Smart-Ptr für Felder. Daher meine Aussage: Die Smart-Pointer für Felder heißen std::vector und std::string.
so ein quatsch. strings stellen zeichenketten dar und vector stellet dynamische arrays dar.
außerdem: vector und string sind im allgemeinen gute sachen und smartpointers sind im allgemeinen schlechte sachen.
-
volkard schrieb:
sven_jo schrieb:
Konrad schrieb:
sven_jo schrieb:
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
SvenDas sind keine SmartPtr sonder ein dynamisches Array und ein String, die verwalten zwar intern auch den benötigten Speicher aber SmartPtr sind etwas anderes.
Vollkommen korrekt! Da C++ Klassen für dynamische Arrays und Strings besitzt, braucht man keine Smart-Ptr für Felder. Daher meine Aussage: Die Smart-Pointer für Felder heißen std::vector und std::string.
so ein quatsch. strings stellen zeichenketten dar und vector stellet dynamische arrays dar.
außerdem: vector und string sind im allgemeinen gute sachen und smartpointers sind im allgemeinen schlechte sachen.
das von jemand, für den alle verallgemeinerungen falsch sind?
smartpointer sind ein mittel wie jedes andere, um probleme zu lösen - sie können nützlich sein; aber sie um der verwendung willen einzusetzen wird eher problem verursachen. das "schlechte" daran ist dann aber immer noch nicht der smartpointer, sondern der programmierer, der ihn benutzt.
-
volkard schrieb:
sven_jo schrieb:
Konrad schrieb:
sven_jo schrieb:
Noch ein Satz zu Feldern & Smart-Pointern: Die Smart-Pointer für Felder heißen std::vector und std::string.
SvenDas sind keine SmartPtr sonder ein dynamisches Array und ein String, die verwalten zwar intern auch den benötigten Speicher aber SmartPtr sind etwas anderes.
Vollkommen korrekt! Da C++ Klassen für dynamische Arrays und Strings besitzt, braucht man keine Smart-Ptr für Felder. Daher meine Aussage: Die Smart-Pointer für Felder heißen std::vector und std::string.
so ein quatsch. strings stellen zeichenketten dar und vector stellet dynamische arrays dar.
außerdem: vector und string sind im allgemeinen gute sachen und smartpointers sind im allgemeinen schlechte sachen.
du schuldest uns aber immernoch eine aufschlüsselung darüber, wieso

-
otze schrieb:
du schuldest uns aber immernoch eine aufschlüsselung darüber, wieso

smartpoiunter tauchen meistens dann auf, wenn man designfehler wegfrickeln muß. mehr dazu im letzten thread über smartpointer.
-
Ein Container polymorpher Objekte ist ein Designfehler? Also bitte ...
-
volkard würde einen Wrapper um den Container schreiben der im Destruktor für jedes Element delete aufruft.
-
ao schrieb:
volkard würde einen Wrapper um den Container schreiben der im Destruktor für jedes Element delete aufruft.
vielleicht würde er auch einen container mit lösch-policy haben. alexandrescu er gelesen hat.
-

-
volkard schrieb:
ao schrieb:
volkard würde einen Wrapper um den Container schreiben der im Destruktor für jedes Element delete aufruft.
vielleicht würde er auch einen container mit lösch-policy haben. alexandrescu er gelesen hat.
alexandrescu smart pointer mag. ihnen einen großen teil von MCPPD eingeräumt hat.
-
Bitte deutsch, wir sind hier nicht im Kindergartenforum.
-
camper schrieb:
volkard schrieb:
ao schrieb:
volkard würde einen Wrapper um den Container schreiben der im Destruktor für jedes Element delete aufruft.
vielleicht würde er auch einen container mit lösch-policy haben. alexandrescu er gelesen hat.
alexandrescu smart pointer mag. ihnen einen großen teil von MCPPD eingeräumt hat.
alexandrescu mag vieles mögen. aber ich hab bei ihm keinen schwachsinn gesehen. und mindestens malk bedebkleich wäre es, statt bei einem objekt nachzufragen bei millionen von objekten nachzufragen. und im falle, daß man ein paar sachen aus <algorithm> verwenden mag, gleich mit shared_ptr aufzutrumpfen mit 100% speicheroverhead statt mit zeigern in nem smart container.
Sandkastenuser schrieb:
Bitte deutsch, hier nicht im Kindergartenforum wir sind.
deutsch wir sprechen doch.
-
was wärs denn mit diesem szenario?
class BaseFile{ public: const string& getName(); }; //je nach bs braucht man andere funktionen, also packen wir das in ne policy //alternativ kann man sich hier irgendein anderes szenario ausdenken, an dem polymorphie nützlich ist, zb dass es verschiedene dateitypen gibt template<class FilePolicy> class ConcreteFile:public BaseFile{ public: const string& getName(); }; //da wir keinen template wirrwarr in unsrem code dulden, und polymorphie eh nur ein mittel zum zweck ist, kapseln wir das schön weg class File{ private: BaseFile* file; public: File(BaseFile* file):file(file){} const string& getName(){ return file->getName(); } //dtor lass ich erstmal weg }; //nun brauchen wir ne factory class template<class FilePolicy> class FileFactory{ public: File openFile(std::string& path); }man kann mir zwar als designfehler unterstellen, dass ich File unbedingt auf dem Stack haben will, aber das erleichtert dem benutzer das verwenden dieser Objekte ungemein. Ausserdem ist son stack objekt beiweitem weniger kryptisch als ein smart_ptr.
Wo wir grad bei smart_ptr sind: class File braucht natürlich einen. Hat damit zu tun, dass das ding kopiert werden kann ;). Die frage ist nun, welcher: Da wir hier keine deep copy des objektes brauchen, da dateien einmalig sind, brauchen wir uns net damit zu beschäftigen, dass es keinen smart_ptr gibt, der deep copy unterstützt(*heul*). Andererseits ist es natürlich nicht so, dass wir File überhaupt nicht kopieren, das ist einerseits durch die Factory gegeben, andererseits werden solche Handles gerne mal rumgereicht, sodass ein delete im dtor nicht mehr ausreicht(bzw ein scoped_ptr, btw: ein scoped_ptr mit deep copy policy wär mal richtig nice, dann könnte man ihn sogar innerhalb von Objekten sinnvoll nutzen).
auto_ptr schließen wir auch aus, weil gerne mehrere klassen die möglichkeiten haben wollen, auf diese daten zuzugreifen. Bleibt also nurnoch der shared_ptr, weil wir hier referenzzählung brauchen.class File{ private: boost::shared_ptr<BaseFile> file; public: File(boost::shared_ptr<BaseFile> file):file(file){} const string& getName(){ return file->getName(); } //dtor brauch ich nimmer };