Forum: PC-Programmierung C++ Broker Pattern und Smartpointer


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jasson J. (jasson)


Lesenswert?

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
1
class BrokerBase
2
{
3
public:
4
    BrokerBase();
5
6
    void RegisterServer(ClientServerBase* _server);
7
    void Serve(int& itterration, float _pos);
8
9
    void RegisterClient(ClientServerBase* _client);
10
    void Request(int& itterration);
11
12
private:
13
    list<ClientServerBase*> serverList;
14
    list<ClientServerBase*> clientList;
15
16
    unsigned int serverCntr;
17
    int curItterration;
18
};

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?


von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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"?

von Harald K. (kirnbichler)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Harald K. (kirnbichler)


Lesenswert?

Niklas G. schrieb:
> Nur weil man etwas nicht versteht, ist es nicht falsch oder unnötig.

Sicher, das muss es sein.

von Klaus H. (klummel69)


Lesenswert?

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?

von Oliver S. (oliverso)


Lesenswert?

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

von Jasson J. (jasson)


Angehängte Dateien:

Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Jasson J. schrieb:
> verzweigte Kettenstruktur

Also ein Graph? Gerichtet oder ungerichtet? Azyklisch oder nicht?

von Jasson J. (jasson)


Lesenswert?

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?"

von Oliver S. (oliverso)


Lesenswert?

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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> noch raw pointer

Und wie modellierst du einen non-owning Pointer der auch Null sein kann?

von Roger S. (edge)


Lesenswert?

Niklas G. schrieb:
> Und wie modellierst du einen non-owning Pointer der auch Null sein kann?
std::weak_ptr

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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...

von Oliver S. (oliverso)


Lesenswert?

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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Roger S. (edge)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Roger S. (edge)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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...

von Jasson J. (jasson)


Lesenswert?

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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Falk S. (falk_s831)


Lesenswert?

> 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.

von Franko S. (frank_s866)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

Falk S. schrieb:
> Overengineering in Lauerstellung.

Nee, klassisches Patternproblem. Wir nehmen eine Lösung (Brokerpattern), 
und zimmern uns dazu ein (un)passendes Problem.

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Husch-Husch, zurück zu euren C89-Compilern, es warten Segfaults und 
Speicherlecks darauf debuggt zu werden!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.