std::auto_ptr vs. smart pointer aus boost::smart_ptr
-
Tja, meine Software wird nicht vermarktet (soooo gut ist mein Game dann doch wieder nicht
).
Das Haupthinderniss ist ja IMHO, dass sich das Framework keiner installieren will, bzw. sowieso schon keiner gewillt ist, sich wegen meinem Müll das .Net Framework zu ziehen.
-
Also ich hab dotNET 1.1 installiert, und wenns sein muss installiert es auch jeder. Wäre ja wie wenn sich die Leute dafür entscheiden für Doom3 kein DirectX9 zu installieren - "Nein das will ich nicht, soll der Depp die GDI benützen :p"
MfG SideWinder
-
Ja so läuft's aber seltsamerweise. Jedes nicht .Net Drecksprogramm bringt seine 20 dll's mit, die in der Registry eingetragen werden und ins Systemverzeichnis kopiert werden, wo gleich mal andere Versionen dieser dll kommentarlos ersetzt werden, bis gar nichts mehr läuft, aber das wird toleriert, kommt ja so ein schöner Setup-Bildschirm, der wird schon alles richtig machen.
Aber wenns darum geht, das .Net Framework zu installieren, was auch nur ne Sammlung von Bibliotheken und Diensten ist (und so nebenbei die zukünftige System API), wird rumgememmt, "ne des spioniert mir alles aus", "Microsoft will die Weltherrschaft", was auch immer.Mei, wir leben in ner Welt, wo lauter DAUs keine Ahnung haben was gut ist und im selben Moment, wie sie sich weigern, irgendnen Dreck wieder installieren, der alles im System verstellt.
Kann man nicht ändern. Naja wenigstens hab ich's jetzt endgültig geschafft, den Thread Off-Topic werden zu lassen. Auch was wert.
-
Was hat den C++/CLI mit Windows zu tun? Klar, MS selbst supportet nur Windows. Aber .NET gibts auch von Novel, weil .NET (die Basis) halt auch schon ISO-Standard ist. C++/CLI ist halt eine weitere Sprache und ich möchte behaupten, wir C++-Fans können MS dafür nur danken das sie C++ einen so hohen Stellenwert geben.
.NET ist unter Windows mit zwei Klicks installiert. Unter Linux und Unix von Novell wird es bestimmt auch so sein? Habe Mono noch nie installiert, aber dürfte doch auch nicht so schwer sein?
-
operator void schrieb:
Wobei ich aber noch eine Frage hätte. Theoretisch muss für auto_ptr<T> der Typ T wie für alle std-templates vollständig definiert sein, oder?
Nicht nur theoretisch. Du brauchst die vollständige Definition von T da sonst der Destruktor von std::auto_ptr undefiniertes Verhalten hat.
@Optimizer
Ein GC hat mit dem Thema nichts zu tun. Ein GC hilft dir herzlich wenig, wenn es dir um deterministische Resourcenfreigabe geht.Mal lesen: http://blogs.msdn.com/hsutter/
Ansonsten wäre es schön, wenn du deine Hass-Tiraden auf einen anderen Thread (am Besten im OT-Forum) konzentrieren könntest.
-
HumeSikkins schrieb:
Nicht nur theoretisch. Du brauchst die vollständige Definition von T da sonst der Destruktor von std::auto_ptr undefiniertes Verhalten hat.
Stimmt. Naja, mir wäre es lieber, das Aufrufen von factory() würde dann in Dateien, in denen der Destruktur nicht definiert ist, zu einem Compilerfehler führen (boost::safe_delete machts vor ;)) - das würde (nochmal in meinem konkreten Fall) die Compilezeiten minimal reduzieren, aber da gibt's wirklich Schlimmeres
-
HumeSikkins schrieb:
@Optimizer
Ein GC hat mit dem Thema nichts zu tun. Ein GC hilft dir herzlich wenig, wenn es dir um deterministische Resourcenfreigabe geht."Herzlich wenig" heißt nicht "gar nicht". "Nichts damit zu tun", halte ich zumindest für eine kleine Übertreibung. Ein GC kann mir zumindest etwas bieten, was mir kein C++ Destruktor und keine Referenzzählung bieten kann: Eine einigermaßen hohe Wahrscheinlichkeit, dass irgendwann (vielleicht netterweise in absehbarer Zeit) die Resourcen freigegeben werden, über den Objekt-finalizer. Achtung: Ich halte das nicht für eine gute Idee oder gar eine Erleichterung. Es ist lediglich eine zusätzliche Sicherheit, die aber schon mal besser ist als gar nichts.
Amsonsten schaut es überall gleich schlecht aus: Ein Freigeben wichtiger Resourcen zu einem geeigneten Zeitpunk muss der Programmierer verantworten. Ich kann mir keinen Fall vorstellen, wo ich genau für die Dauer eines Scopes eine Socket-Verbindung brauche.
Referenzzählung bringt bei Objekten auf dem Heap IMHO genauso wenig?Zumindest bei trivialen Resourcen wie Arbeitsspeicher tut ein GC seinen Dienst, und das zuverlässiger als seine Kollegen. Referenzzählung funktioniert spätestens bei zirkulären Abhängigkeiten (die auch über Umwege auftreten können) nicht mehr.
Das denke ich zumindest darüber. Ich lasse mich gerne überzeugen, wenn du mir irgendwie beweisen kannst, dass es dir mit den boost-Pointern gelingt, einen garantiert stattfindenden und rechtzeitigen Aufruf eines Destruktors, von einem Objekt mit unbestimmter Lebenszeit sicherzustellen.
Diese Gedanken sind jetzt ausschließlich auf Sicherheitsaspekten gebaut.Ansonsten wäre es schön, wenn du deine Hass-Tiraden auf einen anderen Thread (am Besten im OT-Forum) konzentrieren könntest.
So schlimm war es jetzt doch nicht, oder? Ich habe meine Meinung, wie ich denke, einigermaßen frei von negativen Emotionen rübergebracht. Gewiss, sarkastisch war es schon. Aber dies möge man mir bitte verzeihen, da es eh an niemanden persönlich gerichtet war.
btw., die Aussagen (oder Standpunkte), die ich kritisiert habe, existieren wirklich (auch in diesem Forum) und es ist mir unbegreiflich?
"zum Glück ist bei XP das .Net Framework nicht schon dabei" - oh man. Hoffentlich kriegen solche Leute ihr Longhorn dann ohne Framework, also praktisch ohne Systemapi.
-
Optimizer schrieb:
Zumindest bei trivialen Resourcen wie Arbeitsspeicher tut ein GC seinen Dienst, und das zuverlässiger als seine Kollegen.
hä?
ich hab keine speicherlöcher. so gar nicht. der gc brächte mir null sicherheit. nur den komfort, was nicht machen zu müssen, was mir keine belastung darstellt.
-
Gut, dafür gibt es ja auch Mittel und Wege. Ich habe ja auch keine Memory Leaks und kann das auch sicherstellen. Vielleicht hätte ich schreiben sollen "automatisch sicherer", obwohl "sicherer" bestimmt nicht falsch ist.
Leaks sind ja auch nicht die einzige Gefahr von manueller Speicherverwaltung. Ist mir ehrlich gesagt schon ab und zu mal passiert, dass ich Objekte gelöscht hab, die woanders noch referenziert wurden. Da setz ich mich dann hin und viiiieeel Zeit geht drauf, bis mir ein gutes System eingefallen ist, wie und wann ich den Speicher am besten freigebe.
-
Optimizer schrieb:
Da setz ich mich dann hin und viiiieeel Zeit geht drauf, bis mir ein gutes System eingefallen ist, wie und wann ich den Speicher am besten freigebe.
In diesen ganz seltenen Situationen kann man ja Refcounting machen.
Und nur deshalb (weil man uU einmal in so eine situation kommen koennte (mir ist dies noch nicht passiert)) einen GC fordern? naja...Erklaer mal lieber warum man in C++ einen GC braucht? Bisher sind alle Argumente von dir abgeschmettert worden
faellt noch etwas besseres ein?
-
Refcounting ist keine Garantie für gar nichts (siehe oben). btw, ich bin nicht der Meinung, dass man für C++ einen GC "braucht". "Brauchen" tut man sowieso überhaupt keinen...
Oder ich würde zumindest für C++ keinen wollen. Die Diskussion war auch ursprünglich überhaupt nicht auf C++ bezogen, sondern auf Arten der Resourcenverwaltung allgemein.
Ich bin auch wie Hume der Meinung, dass wenn es sich nicht gerade um triviale Resourcen wie RAM handelt, ein GC nicht viel bringt (außer eine Rettung in letzter Not, über finalizer, guter Stil ist das sicher nicht).
Das Eigentliche, was mich ein bisschen verwirrt ist eine anscheinend vorherrschende generelle Abneigung gegen Laufzeitumgebungen (insbesondere auch unter den Endkunden, siehe ursprüngliche Diskussion über Verbreitung des .Net Frameworks). Für C++ will ich gar keine haben, managed C++ gefällt mir auch kein Stück. Aber darum gings ja auch nicht wirklich.Bisher sind alle Argumente von dir abgeschmettert worden
Meinst du meine Argumente für garbage collection? wo sind die abgeschmettert worden? Refcounting ist kein Ersatz, scope-Destruktoren schon gleich gar nicht. Die einzigen Gegenargumente, die mir aufgefallen sind, waren, man hätte ja dies und das, aber ich habe glaub ich ausreichend begründet, warum dies und das kein Ersatz ist.
-
Optimizer schrieb:
die mir aufgefallen sind, waren, man hätte ja dies und das, aber ich habe glaub ich ausreichend begründet, warum dies und das kein Ersatz ist.
mir ist als begründung nur aufgefallen "aber manche machen dauernd löcher und der gc würde manchmal per finalizer mir was retten".
die meisten können nicht mal c++, sollten wir nicht besser basic nehmen, weil mehr leute es können?
falls wir uns drauf einigen können, nicht die leute, die c++ nicht können, zum maß zuz nehmen, warum nicht gleich auch drauf einigen, nicht die leute zu nehmen, die c++ kaum können?
-
Ok, einigen wir uns darauf, dass kein Programmierer jemals wieder einen Fehler machen soll.
mir ist als begründung nur aufgefallen "aber manche machen dauernd löcher und der gc würde manchmal per finalizer mir was retten".
Sollte eher so gemeint sein: "Was man nicht selber machen muss, kann man auch nicht falsch machen".
-
Optimizer schrieb:
"Was man nicht selber machen muss, kann man auch nicht falsch machen".
Und genau deshalb, hat man RAII.
Da muss man nichtmehr freigeben, weil das automatisch geschieht.
OK, man muss sich merken, dass man RAII verwenden soll - aber dass sollte gerade noch gehen.
-
Was ist RAII? Das beim Verlassen des scopes der Destruktor aufgerufen wird, oder?
Das kann ich fast nie brauchen. Wenn ich ne Socket-Verbindung aufbaue, dann brauch ich die halt so lange, wie ich sie brauche. Wenn es nicht gerade ein Chat-Client simpelster Art ist, hilft dir das doch kaum. Ich weiss nicht, was du für Erfahrungen gemacht hast, aber bei den meisten meiner Objekte, die relevante Resourcen verwalten, ist die Lebenszeit nicht absehbar -> auf den Heap -> ans delete denken müssen.
Ein GC löst das Problem natürlich genauso wenig, zumindest rechtzeitig gibt der das bestimmt auch nicht frei. Ich sehe für realistisches Anwendungsfälle keinen Weg, da rum zu kommen, dass der Programmierer das selber in die Hand nehmen muss.
-
Optimizer schrieb:
Was ist RAII? Das beim Verlassen des scopes der Destruktor aufgerufen wird, oder?
Nein. RAII steht für Resource Acquisition Is Initialisation und bedeutet soviel, dass eine Resource in einem Konstruktor eines Objekts angefordert wird und im Destruktor freigegeben wird.
Am effektivsten sind RAII-Objekte, wenn es sich dabei um lokale Objekte handelt. Der Punkt ist aber, dass man pro Resource ein Objekt hat, das diese Resource managed.Wenn ich ne Socket-Verbindung aufbaue, dann brauch ich die halt so lange, wie ich sie brauche
Wenn es nicht gerade ein Chat-Client simpelster Art ist, hilft dir das doch kaum. Ich weiss nicht, was du für Erfahrungen gemacht hast, aber bei den meisten meiner Objekte, die relevante Resourcen verwalten, ist die Lebenszeit nicht absehbar -> auf den Heap -> ans delete denken müssen.Dieser Logik kann ich nicht folgen. Normalerweise ist irgendeine Klasse letztlich Besitzer der Socket-Verbindung. Wenn es Zeit wird aquiriert die Klasse die Socket-Verbindung (nicht notwendigerweise im Ctor) und im Destruktor wird die Socket-Verbindung wieder freigegeben. Sollte die Klasse noch andere Resourcen managen, deligiert sie diesen Vorgang an ein RAII-Objekt und hält ein solches als Member.
Ein Objekt der Klasse ist dann z.B. ein lokales Objekt in main. Oder aber ich habe ein Objekt auf dem Heap und verwalte diese irgendwo (z.B. in main) über einen auto_ptr (oder ähnliches).Ich sehe für realistisches Anwendungsfälle keinen Weg, da rum zu kommen, dass der Programmierer das selber in die Hand nehmen muss.
Mir scheint du hast bisher wenig gute C++ Programme gesehen.
-
Hat das einen Vorteil gegenüber den nichtdeterministischen Destruktoren? Vielleicht brauchst du von den 9832475 Socketverbindungen, die du indirekt verwaltest, die Hälfte schon nach kurzer Zeit nicht mehr. Aber automatisch werden sie auch nur gekickt, wenn du das ganze Chief-Objekt (
) deletest und damit praktisch überhaupt keine mehr hast.
Macht für mich keinen Unterschied, wenn du nicht daran denkst, die, die du schon früher nicht mehr brauchst, schon vorher freizugeben, kommt auch erst am Schluss in letzter Instanz der Destruktor, der dann alles killt.Ich sehe den Vorteil nicht, das kann mein nichtdeterministischer Destruktor am Programmende dann auch und mit hoher Wahrscheinlichkeit schon früher.
-
warnung: dieses posting hat keine relevante aussage. das lesen desselben könnte ermüdend wirken.
Optimizer schrieb:
Das kann ich fast nie brauchen. Wenn ich ne Socket-Verbindung aufbaue, dann brauch ich die halt so lange, wie ich sie brauche. Wenn es nicht gerade ein Chat-Client simpelster Art ist, hilft dir das doch kaum.
kommt drauf an, wie man ansetzt. nehmen wir also keinen simelsten chat-client, sondernen nen simpelsten chat-server.
der listening socket kann durchaus auf den stack.
immer, wenn der ne verbindung aufgemacht kriegt, muss was entstehen. naja, ne sitzung halt. die hat vermutlich nen (lebenden!) socket und ein paar userdaten (vielleicht bloß die iser-id).
dann ist zunächst mal zu prüfen, wer dieses sitzungsobjekt löschen sollte. also mitkriegen tut's zuerst der socket, wenn die sitzung beendet wird. der kann es mit sicherheit der sitzung weitersagen. die sitzung kann jetzt viele wege gehen. zum beispiel das beliebte "delete this;". gruselig. aber welche alternativen bleiben? sie könnte dem globalen verbindungskiller sagen "kill mich, wenn du zeit hast". sie könnte false zurückgeben in der funktion, die irgendein manager aufgerufen hatte (ich gehe ncht von einem thread pro session aus). sie könnte ne exception werfen.
vermutlich ist hier am saubersten, false zurückzugeben. dann kann leicht derjenige, der false empfangen hat die sitzung löschen. braucht man dazu zeiger auf sitzungen? nein. sie könnten genausogut in nen std::vector reinkonstruiert werden. ob der manager sitzungs-zeiger oder sitzungs-ids (arrayindizes) benutzt, ist ja egal.
ich fürchte, deine aussageIch weiss nicht, was du für Erfahrungen gemacht hast, aber bei den meisten meiner Objekte, die relevante Resourcen verwalten, ist die Lebenszeit nicht absehbar -> auf den Heap -> ans delete denken müssen.
ist mir nicht nachvollziehbar.
ich hab gerade einen programmausdruck vor mir. mein homepage-uploader. die wichtigsten klassen heißen (denke, das aufzählen der klassennamen macht weitgehend klar, wie er innen funktioniert): Internet FtpConnection, CriticalSection, Lock, Semaphore, Event, Job, JobQueue, JobCreateDir, JobSyncDir, JobCreateFile.
der ablauf ist so, daß einige threads im sekundenabstand gestartet werden, die thread holen sich ober ne durch semaphore gesteuerte queue aufträge, bestimmte aufträge wie JobSyncDir können beim abarbeiten witere aufträge erzeugen (u.a. JobSyncDir für jedes unterverzeichnis).
also ein wildes umhergewerfe von jobs, sie werden zum größten teil von parallelen threads erzeugt und es wäre sogar nett, wenn sie am ende verschwinden würden. geht natürlich nur über refcounting smart pointers. jeder job merkt sich, welche subjobs er erzeugt hat und hält sie dadrch am leben usw. nee, scherzchen gemacht. ich schreib dir jobs einfach in die globale JobQueue rein und gut ists. die ist auch für's löschen zuständig.
welche ressourcen bindet ein job? tja, gar keine. die basisklasse Job ist leer und sachen wie JobSyncDir haben halt nen string drin, den verzeichnisnamen. soweizt zu den wichtigen resourcen, die auf dem heap liegen.
das handle HINTERNET... (man muss bei win für die <wininet.h>-sachen ne inernetverbindung locken) lebt in der main() als auto-variable, jeder thread hat ne eigene ftp-connection, geht auch gut als auto-variable. die jobqueue ist der einfachheit halber global, sie könnte auch in der main leben, und hat ein wenig speicher und ne semaphore. das event zum beenden aller threads ist wieder global.
nö, alles wichtige legt auf dem stack (oder global) und nix wichtiges ist auf dem heap. zufall?
der andere ausdruch vor mir ist mein html-generator. da gibts außer speicher nur eine ressource, ein file. ein ifstream auf dem stack.so komm ich nicht weiter. ob ich mich daran erinnern kann, daß ich viele wichtige ressourcen auf den heap geworfen hab? nee, eigentlich nicht. also sachen wie dateien, semaphoren, critical sections, und so liegen eigentlich immer auf dem stack. bloß bei sockets sehe ich freispeicher, aber da hat man ja immer ne liste aller offenen sitzungen. dieser liste sage ich dann, daß sie beim sterben die noch offenen verbindungen gleich auch killen soll. will sagen, es ist wenig, daß man mal probleme hätte, zu wissen, wer was löschen muss. die meisten ressourcen liegen eh nicht im freispeicher. die, die doch drin liegen, gehören einer datenstruktur, die nicht drin liegt. fertig eigentlich. letztendlich zieht RAII total gut.
und du machst ja auch nix anderes. um du auf mene oder auf deine methode dafür sorgst, daß der sterbende container die zeiger alle deleted, ist ja egal. du scheinst allerdings von mehr zeigern auszugehen, die im wald rumstehen und nicht brav in containern liegen. kann ich wieder nicht nachvollziegen, warum man die nicht in nen container stopft.
-
Hallo,
keiner sagt, dass RAII dich davor schützt dein Gehirn einsetzen zu müssen. Wenn du zu einem Zeitpunkt t eine Resource X nicht mehr brauchst, dann musst du dies schon irgendwo explizit codieren. Zumindest falls t nicht zufälligerweise mit einem Block-Ende zusammenfällt.
RAII kann aber garantiert dafür sorgen, dass an irgendeinem festen Zeitpunkt t1 alle Resourcen wieder freigegeben werden -> Keine Resource-Leaks.
Sprich: RAII schützt dich vor Resource-Leaks (also vor dem GAU-Fall) es implementiert aber nicht automatisch eine bestimmte Anwendungslogik.Zu deinem Beispiel: Ich würde die einzelnen Verbindungen z.B. durch Connection-Objekte repräsentieren. Diese halte ich alle in einem Container, dessen Dtor alle Connections freigibt -> keine Resource-Leaks.
Außerdem implemtiere ich in den Connection-Objekten sowas wie ein "destructive close". Wird die Verbindung beendet (entweder vom Client oder vom Server) wird automatisch auch die Resource (z.B. der Socket) freigegeben.
Das ist aber eine Designentscheidung und eine solche kann dir kein GC dieser Welt abnehmen.BTW: RAII ist besonders in Verbindung mit Exceptions sehr wertvoll und der Grund dafür, dass man in C++ a) viel weniger try{}-catch{}-Blöcke sieht als zum Beispiel in Java und b) kein finally braucht.
-
Optimizer schrieb:
Hat das einen Vorteil gegenüber den nichtdeterministischen Destruktoren? Vielleicht brauchst du von den 9832475 Socketverbindungen, die du indirekt verwaltest, die Hälfte schon nach kurzer Zeit nicht mehr. Aber automatisch werden sie auch nur gekickt, wenn du das ganze Chief-Objekt (
) deletest und damit praktisch überhaupt keine mehr hast.
falsch.
natürlich werden sockets immer so früh wie möglich gelöscht. noch in der selben zeitscheibe, wo man vom disconnect was mitgekriegt hat. also gleich, unverzüglich, sofort, unmittelbar und eilig. das cheif-objekt als besitzer hat alle zu löschen, die man nicht vorher selber gelöscht hat, also insbesondere im falle einer exception, die bis oben hin durchschlägt.