Hoí da
-
>Kontext
ich schreibe an einer Struktur, die sich am Broker-Pattern orientiert
und bidirektional funktioniert - also Clients können beim Broker Daten
requesten und der reicht die Anfrage weiter.
Es gibt also Broker, welcher Clients mit Servern verbindet. Dabei kann
ein Broker mehrere Server und mehrere Clients haben und Client und
Server sind immer in einer Klasse kombiniert, da es eine Kettenstruktur
mit Verzweigungen wird.
Der Broker führt etwas Logik aus, bevor er die Daten der Server an die
als Client angemeldeten Objekte weiter gibt.
>Frage
In den Guidelines gibt es eine Regel 20, welche sagt
>>Use unique_ptr or shared_ptr to represent ownership
Ich bin noch nicht sicher, ob der Broker in dem Sinne eine Ownership an
den Servern und Clients hat, aber das automatisierte Memorymanagement,
welches mit Smartpointern kommt, würde dafür sorgen, dass ein
ClientServer-Object deleted wird, wenn seine letzte Instanz bei einem
Broker entfernt wurde.
>> Von der Warte her, wäre ja sinnvoll sharepointer zu verwenden und die list´s of
raw pointer durch smartpointer typen zu ersetzten?
Viele Grüße
Jasson J. schrieb:> Ich bin noch nicht sicher, ob der Broker in dem Sinne eine Ownership an> den Servern und Clients hat,
Wenn der Broker Ownership an beiden hat - wann werden dann überhaupt
jemals Server und Clients gelöscht? Ich denke mal der Broker ist eine
Art globale Instanz?
ClientServerBase ist eine gemeinsame Basisklasse für Clients und Server?
Das klingt verkehrt.
Jasson J. schrieb:> list<ClientServerBase*> serverList;
list<> sollte man nur relativ selten verwenden, meistens lieber
vector<>.
Jasson J. schrieb:> unsigned int serverCntr;
Wäre da nicht ein std::size_t sinnvoller?
Harald K. schrieb:> Aus irgendeinem Grund muss ich jetzt an diesen Kommentar hier denken:
Wenn jemand Quantenphysik macht, kommst du dann auch vorbei und sagst
"Früher hat uns F=m*a gereicht"?
Niklas G. schrieb:> Wenn jemand Quantenphysik macht
Nein. Aber wenn geistige Onanie auf ein Podest gestellt wird, frage ich
mich schon, ob das wirklich nottut. Und wenn ich mir ansehe, wie
heutzutage manche Software geschrieben wird, dann ... tja, sorry, aber
dann erkenne ich gelegentlich Parallelen.
Harald K. schrieb:> Nein. Aber wenn geistige Onanie auf ein Podest gestellt wird, frage ich> mich schon, ob das wirklich nottut
Nur weil man etwas nicht versteht, ist es nicht falsch oder unnötig.
Versuche zuerst alle Funktionalitäten (nicht Funktionen im Sinne der
Programmiersprache) zu sammeln. Dann erkennt man meistens schnell dass
bestimmte Konstrukte passen oder nicht passen.
* Wie sieht es mit einem "Unregister" von Server oder Client aus? Gibt
es das nicht?
* Wie werden Fehler signalisiert? Was passiert bei Timeouts?
* Was ist das Kriterium, welcher Client mit welchem Server sprechen
soll?
* Welche Funktionalitäten soll eine ClientServer Klasse haben?
Jasson J. schrieb:> Es gibt also Broker, welcher Clients mit Servern verbindet. Dabei kann> ein Broker mehrere Server und mehrere Clients haben und Client und> Server sind immer in einer Klasse kombiniert, da es eine Kettenstruktur> mit Verzweigungen wird.
Verstehe ich nicht. Gibt es eine 1:1 Beziehung zwischen Server und
Client, sprich ein Server kann immer nur mit einem Client kommunizieren?
Die einfache Frage wurde ja oben schon gestellt: wer oder was hat die
ownership für Server und clients?
BrokerBase::RegisterServer bekommt ja eine Instanz übergeben. Wo kommt
die her?
Soll BrokerBase die Ownership für die ServerInstanz übernehmen, und im
Extremfall die ServerInstanz deleten, wenn die nicht mehr benötigt wird,
oder passiert das ausserhalb?
Oliver
Niklas G. schrieb:> Jasson J. schrieb:>> list<ClientServerBase*> serverList;> list<> sollte man nur relativ selten verwenden, meistens lieber> vector<>.
Stimmt - guter Punkt
> Jasson J. schrieb:>> unsigned int serverCntr;> Wäre da nicht ein std::size_t sinnvoller?
Da hab ich den Zweck nicht als Kommentar geschrieben - der Member zählt
nicht die Anzahl der registrierten Server.
Weil es mir beim Start vom Thread nur um die Ownership-Frage ging, hab
ich die Gesamtidee nicht beschreiben, um den thematischen Fokus zu
behalten.
-
Ich will Elemente schreiben, mit denen ich eine verzweigte
Kettenstruktur aufbauen kann, dem Prinzip folgend wie im Bild. Sever und
Client sind dabei mehr als eine Input und eine Output-Seite des selben
Objektes zu sehen, deren Seiten jeweils zu verschiedenen Brokern gelinkt
sind. Dabei handelt es sich nicht um Server und Clients im Sinne von
PC´s und Handys, sondern eher um die Ausdrücke aus dem
Client-Server-Pattern.
>Lirum Larum - der Broker kann von nem Client gepingt werden, Daten bereit zu
stellen - in meiner Anwendung ganz simpel ein float Wert. Den Ping reicht er
erstmal bis nach oben weiter an alle Server die registiert sind. Die Daten / Werte
die dann kommen addiert er auf und gibt die Summe erst weiter, wenn alle Server
geantwortet haben.
>if(serverCntr == serverList.size())Oliver S. schrieb:> Die einfache Frage wurde ja oben schon gestellt: wer oder was hat die> ownership für Server und clients?> ...> oder passiert das ausserhalb?>> Oliver
Danke auf jeden Fall für die Denkanstöße, beantworten kann ich das
gerade noch nicht.
Niklas G. schrieb:> Also ein Graph? Gerichtet oder ungerichtet? Azyklisch oder nicht?
Auf jeden Fall jetzt schon nah dran und mit einer Überlegung, die ich
noch klären muss, könnte das letztendlich der Fall sein.
Wenn es keine konzeptionelle Notwenigkeit oder sinnvollen Hintergrund
gibt, das das bisschen Logik, was im Moment im Broker ist (damit meine
ich nicht das register und ausstehende unregister), sondern das mit die
im Moment so genannten ClientServer Objekte zu verlagern
-
dann bin ich bei nem Graph angekommen.
Wobei ich glaube, dass das den Character der Eingangsfrage nicht ändert.
Das sich ClientServer-Instanzen gegenseitig besitzen klingt wenig sinnig
- aber das Auto-Delete-Feature / bzw. Memorymanagement via Smartpointer
ist weiterhin attraktiv.
Also die Hausaufgabe an mich bleibt die selbe - "Wem gehören die
Instanzen?"
Jasson J. schrieb:> Das sich ClientServer-Instanzen gegenseitig besitzen klingt wenig sinnig> - aber das Auto-Delete-Feature / bzw. Memorymanagement via Smartpointer> ist weiterhin attraktiv.
Ums nur kurz und knapp zu ergänzen:
Ein C++-Programm benutzt weder new noch delete noch raw pointer.
(Ausnahmen bestätigen, wie immer, die Regel).
Oliver
Roger S. schrieb:> std::weak_ptr
Funktioniert nur bei Objekten die mit shared_ptr verwaltet werden. Das
sind bei weitem nicht alle, insbesondere z.B. die die per unique_ptr
verwaltet werden...
Niklas G. schrieb:> Und wie modellierst du einen non-owning Pointer der auch Null sein kann?Oliver S. schrieb:> Ausnahmen bestätigen, wie immer, die Regel
Oliver
Oliver S. schrieb:> Oliver S. schrieb:>> Ausnahmen bestätigen, wie immer, die Regel
Ein Non-Owning Pointer ist aber keineswegs die Ausnahme, sondern taucht
ständig überall auf. Alleine schon als Iterator in Standard-Algorithmen.
Jasson J. schrieb:> dann bin ich bei nem Graph angekommen.
Naja, ein Graph kann auch unterschiedliche Knoten haben. Also sowohl
Broker und ClientServer können Knoten sein. Bei vielen Implementationen
von Graphen gibt es eine "große" Graph-Klasse welches alle Knoten (und
Kanten) besitzt, z.B. ein schlichter vector<ClientServer>. Wird der
Graph zerstört, sind auch alle ClientServer weg.
Die Frage ist ob das für dich passt oder ob der Graph zwischendurch
"umgebaut" werden soll, also z.B. Teile davon zwischendurch löschen.
Wenn nicht, reicht o.g. simpler Ansatz.
Niklas G. schrieb:> Roger S. schrieb:>> std::weak_ptr>> Funktioniert nur bei Objekten die mit shared_ptr verwaltet werden. Das> sind bei weitem nicht alle, insbesondere z.B. die die per unique_ptr> verwaltet werden...
der unique_ptr hat die funktionalitaet ja schon eingebaut.
Roger S. schrieb:> der unique_ptr hat die funktionalitaet ja schon eingebaut.
Es kann aber logischerweise nur einen unique_ptr auf ein Objekt geben.
Oft braucht man aber noch weitere non-owning-Referenzen auf eine Objekt.
Wenn diese nie Null sein können, nimmt man eine Referenz (&), ansonsten
einen klassischen Pointer.
Niklas G. schrieb:> Oft braucht man aber noch weitere non-owning-Referenzen auf eine Objekt.> Wenn diese nie Null sein können, nimmt man eine Referenz (&), ansonsten> einen klassischen Pointer.
Nachdem man sich die notwendigen Gedanken über die lifetime und
ownership gemacht hat, sind natürlich raw pointer die Lösung für das
dazu passende Problem.
Oliver
Niklas G. schrieb:> Es kann aber logischerweise nur einen unique_ptr auf ein Objekt geben.> Oft braucht man aber noch weitere non-owning-Referenzen auf eine Objekt.> Wenn diese nie Null sein können, nimmt man eine Referenz (&), ansonsten> einen klassischen Pointer.
Es gibt keinen Grund in modernem C++ raw pointer einzusetzen (ausser
vielleicht zum austausch mit low-level code). Mittlerweile sind genug
Sprachmittel vorhanden um korrekteren/sicheren code in C++ zu schreiben,
raw pointer gehoeren definitiv nicht dazu.
Roger S. schrieb:> Mittlerweile sind genug Sprachmittel vorhanden um korrekteren/sicheren> code in C++ zu schreiben,
Welche? z.B. in der Liste von Observern in einem Observer Pattern. Oder
den "parent" Pointer in einer Baumstruktur. Oder die Parameter von
std::equal...
Niklas G. schrieb:> Es kann aber logischerweise nur einen unique_ptr auf ein Objekt geben.> Oft braucht man aber noch weitere non-owning-Referenzen auf eine Objekt.> Wenn diese nie Null sein können, nimmt man eine Referenz (&), ansonsten> einen klassischen Pointer.
Dann gibts noch Shared und Weak Pointer
Jasson J. schrieb:> Dann gibts noch Shared und Weak Pointer
Ja. Aber die sind für die genannten Zwecke völlig ungeeignet. shared_ptr
(und dementsprechend auch weak_ptr) ist sowieso nur was für recht
spezielle Situationen - einen non-owning Pointer braucht man öfter, und
dafür nutzt man m.W. einfach einen klassischen nackten Pointer.
> Roger S. schrieb:>> Mittlerweile sind genug Sprachmittel vorhanden um korrekteren/sicheren>> code in C++ zu schreiben,
Ohne Pointer gehts halt manchmal nicht. Seh ich auch kein Problem darin
- wo unterscheidet sich denn ein 'const T* const' z.B. groß von einem
'const T&', außer dass es auch nullptr werden kann? Klar, sind
plain-refs oder rvaluie-refs besser als Ptr, aber wie oben schon von
Niklas erwähnt - bei nem Baum mit Parent-Pointer und Childlist wirds mit
Smartpointern mitunter schon ziemlich lustig, spätestens wenn die
Referenzzählung nie mehr 0 werden kann.
Und realistisch betrachtet, spätestens beim 3rdParty- oder Legacy-APIs
kommt man oft schlicht nicht drumrum.
> Jasson J.:>> ich schreibe an einer Struktur, die sich am Broker-Pattern orientiert>> und bidirektional funktioniert - also Clients können beim Broker Daten>> requesten und der reicht die Anfrage weiter.
Klingt mir irgendwie nach eierlegender Wollmilchsau-Ansatz, der
genererisch für alle erdenklichen Eingaben magischerweise den Goldenen
Hammer darstellt, kurz gesagt: Overengineering in Lauerstellung.
Warum nicht nen normales MVC-Pattern in der Spielart ECB, dafür aber
ausimplementiert für jeweils ein konkretes Client-Server-Paar. Wenn dann
noch Abstraktion nötig ist, halt einfach den Controller noch polymorph
zu irgendeiner Schnittstelle machen und fertig ist.
Ach du liebe Zeit! Was immer noch für ein Sprachschrott: Raw Pointer,
Unique Pointer, Shared Pointer die im Prinzip Ownerpointer sind, Weak
Pointer, Dexter Pointer, Montagspointer, Weihnachtspointer, Sindney
Pointier.
Glasklarer Designfail, Kernschrott C++ bleibt eben Kernschrott, in der
Sprachdauerbaustelle nix neues.
Wenn man oben schon das vermurkste Diagramm anschaut, weiss man gleich
welche Experten diesen Müll verwenden.
Falk S. schrieb:> Overengineering in Lauerstellung.
Nee, klassisches Patternproblem. Wir nehmen eine Lösung (Brokerpattern),
und zimmern uns dazu ein (un)passendes Problem.
Oliver