Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte



  • @DocShoe sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    @wernersbachr sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    (Eine unschöne Lösung wäre wohl return &(inputNeurons.back()); in createNewInput)

    Und eine fehleranfällige noch dazu. Wenn std::vector Speicher für neue Elemente anfordern muss werden neue Kopien erzeugt und damit werden die alten Adressen ungültig.
    Verpacke dein Neuron in einen std::unique_ptr und gib den Rohzeiger zurück, damit biste auf jeden Fall auf der sicheren
    Seite:

    class NeuralNetwork
    {
       std::vector<std::unique_ptr<WorkingNeuron>> Neurons_;
    public:
       ...
       WorkingNeuron* create_neuron()
       {
          Neurons_.emplace_back( new WorkingNeuron() );
          return Neurons_.back().get();
       }
    };
    

    An deinem sonstigen Interface ändert sich nix, du hast eine saubere Lebenszeitverwaltung und gültige Adressen. Kannst halt leider nur keine Kopie des Vektors zurückgeben, aber das wolltest du ja sowieso nicht 😉

    Die Frage ist halt, was er mit dem Rückgabewert der Funktion machen will. Will er den Pointer irgendwo speichern oder einfach Funktionen des Objekts aufrufen?

    Im ersten Fall wäre es vielleicht besser, mit shared_ptr zu arbeiten, anstatt Roh-Pointer rauszugeben, mit denen man mitunter dumme Dinge machen kann ( delete ). Wenn er nur Funktionen der NeuronenKlasse aufrufen will, wäre vielleicht die Rückgabe einer Referenz besser.
    Ich persönlich bin kein Freund von Roh-Pointern, wenn das "Original" in einem Smartpointer vergraben ist und die Besitzrechte dort liegen.

    Da er aber ganz offensichtlich ein KNN baut ( egal welche Art ), arbeitet er mit Vernetzung, das heißt er will den zurückgegebenen Pointer vermutlich irgendwo anders speichern. In dem Fall wäre ich hier ein Freund vom shared_ptr oder der Rückgabe einer ID, mit der man in der NeuralNetworkklasse eine Referenz auf das originale Objekt ( im unique_ptr) abholen kann.


  • Mod

    @DocShoe sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    Die STL arbeitet mit Kopien, sobald du ein Objekt in std::list einfügst speichert die Liste eine Kopie des Objektes. Daher die unterschiedlichen Adressen.
    Mögliche Lösungen:

    • benutze std::unique_ptr und leg die in einem std::vector ab. Wenn es keinen wichtigen Grund für std::list geben sollte ist std::vector der Container der Wahl. Der rohe Zeiger des std::unique_ptr kann dann zur Verwaltung der Verbindungen benutzt werden

    Wieso sollte vector<unique_ptr<T>> besser als list<T> (oder evtl. forward_list<T>) sein, wenn es nur darum geht, stabile Zeiger auf T zu erhalten? Mir scheint, dass die explizite Indirektion vector<unique_ptr<T>> nur unnötig verkompliziert: Es sei denn, man möchte noch zusätzlich vom random-access profitieren.

    class NeuralNetwork
    {
       std::forward_list<WorkingNeuron> Neurons_;
    public:
       ...
       WorkingNeuron* create_neuron()
       {
          return &Neurons_.emplace_front();
       }
    };
    

    Wenn überhaupt käme ggf. vector<WorkingNeurons> infrage, nämlich dann, wenn nach der Erzeugung keine Neuronen eingefügt oder gelöscht werden sollen.



  • @camper
    Ja, eben. Wenn... dazu hat uns TE aber nix erzählt. Wenn der vektor ein Mal erzeugt und danach nie wieder angefasst wird braucht man auch keine smart_ptr, da gebe ich dir völlig recht.



  • Also Neuronen sollten durchaus noch hinzugefügt werden können, da will ich mich nicht festlegen ehrlich gesagt, zumindest jetzt.

    @DocShoe hast du noch einen Tipp wegen meines obrigen Problems?

    LG



  • @wernersbachr Ich bin zwar nicht DocShoe, aber mein wichtigster Tipp lautet: überleg dir genau, wer die Neuronen besitzt und wo du Verweise auf Neuronen brauchst. Und an welchen Stellen du ggf. die Neuronen kopieren möchtest. Überlege dir, ob ein vector (oder eine Liste, falls das hier besser sein sollte) die Neuronen oder Verweise auf die Neuronen enthalten soll. Ich denke, dass dieses für dich bzw. für deinen Code aktuell das größte Problem darstellt.



  • @It0101
    Ja, da hast du recht. Rohe Zeiger könnten dazu einladen sie zu löschen, wenn man sie nicht mehr braucht.
    Ich kenne die Anforderungen von TE nicht, aber man könnte ein Neuron nicht-kopierbar machen durch Löschen des Kopierkonstruktors und Zuweisungsoperators und stattdessen eine Referenz zurückgeben.

    @wernersbachr
    Du musst den iterator zwei Mal dereferenzieren, da der iterator auf einen std::unique_ptr zeigt.
    Aber denk bitte drüber nach, was wob dir geraten hat.



  • Ich weiß ehrlich gesagt nicht, auf welches Ergebnis ihr genau hinauswollt 🤓
    Würdet ihr die Zeiger oder die Objekte in einem vector verwalten?

    edit: Macht es Sinn, wie ursprünglich zu realisieren, nur anstatt eine Adresse eine Referenz zurückzugeben?



  • @wernersbachr sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    Ich weiß ehrlich gesagt nicht, auf welches Ergebnis ihr genau hinauswollt 🤓
    Würdet ihr die Zeiger oder die Objekte in einem vector verwalten?

    Darum geht es eigentlich:

    @camper sagte in [Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte]

    wenn es nur darum geht, stabile Zeiger auf T zu erhalten?

    Ein vector mit Objekten ist halt nicht stabil bzgl. Zeiger.
    Also sowas in der Art

    A* a = &vec[99];
    

    ist problematisch, weil a ungültig werden kann (z.B. nach einem push_front). Bei einer List hast du das Problem nicht (hatte ich eben auch nicht mehr auf dem Schirm).

    Also entweder vector mit unique_ptr oder list mit Objekten.



  • @wernersbachr sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    Ich weiß ehrlich gesagt nicht, auf welches Ergebnis ihr genau hinauswollt 🤓
    Würdet ihr die Zeiger oder die Objekte in einem vector verwalten?

    Das kommt ganz darauf an 😉

    Wenn du den Vektor ein Mal befüllst und danach nie wieder anfasst:
    Speichere die Objekte im Vektor und gib die Adresse der Objekte zurück.

    Wenn du nur Objekte hinzufügst und niemals entfernst:
    Speichere die Objekte im Vektor und gib den Index des Objekts im Vektor zurück.

    Wenn du den Vektor beliebig verändern willst:
    Speichere smart_ptr (unique_ptr oder shared_ptr) im Vektor und gib Referenzen (oder shared_ptr) der Objekte zurück.

    Zu deinem Edit:
    Nein. Ob Zeiger oder Referenz macht keinen Unterschied, bei einer Kopie wird beides ungültig.



  • @wernersbachr sagte in Objekt über Zeiger ist ein anders, als dasselbe in Liste gespeicherte:

    Ich weiß ehrlich gesagt nicht, auf welches Ergebnis ihr genau hinauswollt 🤓
    Würdet ihr die Zeiger oder die Objekte in einem vector verwalten?

    edit: Macht es Sinn, wie ursprünglich zu realisieren, nur anstatt eine Adresse eine Referenz zurückzugeben?

    Zunächst musst du dir über deine Anforderungen klar werden.

    Willst du Verweise auf NeuronenObjekte irgendwo anders noch speichern? Also braucht eine andere Klasse Zugriff auf das NeuronenArsenal?

    Wie bildest du die Synapsen/Connections ab?

    Wenn du das z.B. so machst:

    class Synapse
    {
    // ... bla bla konstruktoren
    private:
        std::shared_ptr<WorkingNeuron> SenderNeuron, ReceiverNeuron;
        double SynapseWeight = 0, NMDA = 0, AMPA = 0;
    }
    

    dann hast du eine andere Klasse, die in irgendeiner Form Verweise auf zwei Neuronen hat.
    D.h. du brauchst außerhalb der NeuralNetwork-Klasse eine Möglichkeit direkt auf Neuronen zu verweisen. Entweder indirekt über eine ID ( Index im Vector in NeuralNetwork ) oder direkt über Referenzen oder shared_ptr.

    Damit entfällt dann z.B. die std::unique_ptr-Lösung.
    Wenn die Menge an Neuronen konstant ist, dann geht das mit Referenzen am schönsten, ansonsten mit shared_ptr.

    Sobald du dir über deine Anforderungen klar geworden bist, kristallisiert sich in aller Regel eine "beste Lösung" raus.


Anmelden zum Antworten