unique_ptr::reset(p)



  • Im Standard zu c++14(20.8.1.2.5) steht:

    void reset(pointer p = pointer()) noexcept;
    3 Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, and shall not throw exceptions.
    4 Effects: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not
    equal to nullptr, calls get_deleter()(old_p). [ Note: The order of these operations is significant because the call to get_deleter() may destroy *this. — end note ]
    5 Postconditions: get() == p. [ Note: The postcondition does not hold if the call to get_deleter()
    destroys *this since this->get() is no longer a valid expression. — end note
    

    Um was für *this geht es in Punk4 und warum kann es durch den deleter zerstört werden?


  • Mod

    Es ist der unique_ptr selbst gemeint. Das vom Pointer gehaltene Objekt könnte ja theoretisch diesen Pointer selbst beinhalten. Daher muss das Setzen der neuen Ressource erfolgen, bevor die alte Ressource freigegeben wird, damit man sich nicht versehentlich selbst zerstört, bevor man alles erledigt hat.



  • @SeppJ sagte in unique_ptr::reset(p):

    Es ist der unique_ptr selbst gemeint. Das vom Pointer gehaltene Objekt könnte ja theoretisch diesen Pointer selbst beinhalten. Daher muss das Setzen der neuen Ressource erfolgen, bevor die alte Ressource freigegeben wird, damit man sich nicht versehentlich selbst zerstört, bevor man alles erledigt hat.

    Ich bin etwas verwirrt. Du meinst der Pointer P zeigt auf Objekt o und o enthält einen member der an dieselbe Adresse wie p zeigt? Warum sollte das den unique_ptr zerstören?

    Kann es nicht eher sein, dass der deleter Teil des Objektes ist und durch dessen Zertörung verschwindet?


  • Mod

    Es sind sicher auch jede Menge andere Kombinationen möglich. Jedenfalls könnte direkt oder indirekt irgendwie der unique_ptr selbst durch den Destruktor zerstört werden. Es geht letztlich darum, dass der unique_ptr ihm fremden Code aufruft und er daher nicht sicher sein kann, was die Postconditions dieses Codes sind und ob sie nicht eventuell den unique_ptr selbst irgendwie betreffen.

    Ich hatte dieses Szenario gemeint, was mir am plausibelsten erschien, wie man zu so einem Zustand kommen könnte, ohne aktiv bösartigen Code in den Destruktor zu packen:

    
    #include <iostream>
    #include <memory>
    using namespace std;
    
    struct SelfReference
    {
      unique_ptr<SelfReference> self;
      SelfReference(): self(this) { cout << "Created at " << this << '\n'; }
      ~SelfReference() {cout << "Destroyed at " << this << '\n';}
      void self_destruct() {self.reset(nullptr);}
    };
    
    int main()
    {
      SelfReference *s = new SelfReference;
      s->self_destruct();
    }
    

    Das funktioniert einwandfrei. Würde der unique_ptr das reset nicht in der Reihenfolge durchführen wie er es tut, würde er sich selbst die Interna wegschießen, die er noch bräuchte. Man kann das simulieren, indem man Zeile 11 zu

     void self_destruct() {self.reset(nullptr); self.reset(nullptr);}
    

    ändert. Das zweite Reset greift dann auf die Interna des nicht mehr existierenden unique_ptr zu, was dann in der Regel einen Segfault auslösen sollte.



  • @SeppJ Danke


Anmelden zum Antworten