2015-01-15 13 views
7

Es könnte thusly realisiert werden:Warum hat std :: weak_ptr nicht operator->?

std::shared_ptr<T> operator->() { 
     auto shared = lock(); 
     if(shared == nullptr) { 
      throw std::bad_weak_ptr(); // or some other exception 
     } 
     return shared; 
    } 

Live Demo

Warum haben die Autoren von weak_ptr entscheiden nicht operator- haben>? (Sie müssen daran gedacht haben)

Ich kann mir mögliche Gründe vorstellen, aber ich frage mich, was der offizielle Grund ist, wenn einer existiert. Mögliche Ursachen:

  • Entmutigen zusätzliche Erhöhung/Verminderung der Referenzzähler für mehrere Anrufe
  • explizite Sperren fördern, anstatt (etwas versteckt) Ausnahmen

Wenn Sie sind verwirrt über die gesamte Lebensdauer des zurück Shared_ptr Siehe this paper.

Auch fragte jemand, warum sollte man einen weak_ptr verwenden, wenn Sie erwarten, dass es nicht abgelaufen ist? Antwort: Zyklen.

Antwort

9

Die original proposalweak_ptr enthielt keine Überladung von operator->.

Ich habe seit dem Protokoll von jedem Treffen seitdem nicht geschaut, aber habe gefolgt, was besprochen worden ist, und erinnere mich an eine Erwähnung von niemandem vorgeschlagen, dass es hinzugefügt werden sollte. Daher ist der "offizielle" Grund, warum es nicht vorhanden ist, wahrscheinlich größtenteils, dass niemand vorgeschlagen hat, dass es hinzugefügt wird.

Wenn Sie zurück zum sehr Anfang gehen wollen, die meisten dieser stammt von John Ellis und David Detlef Safe, Efficient Garbage Collection for C++ Papier, von Usenix 1994, dass ein weakptr Typ in seiner Anlage B enthalten, die etwas anders ist (weakptr::pointer kehrt ein Zeiger direkt, oder ein Nullzeiger, wenn der Zeiger bereits zerstört wurde), aber immer noch keine Operatorüberladung verwendet, um die Aufgabe zu erledigen.

Greg Colvin schrieb die original proposal to add counted_ptr zum Standard. Sein counted_ptr war im Wesentlichen äquivalent zu dem, was jetzt shared_ptr genannt wird, enthielt jedoch nichts, was zu weak_ptr analog ist.

Kurz nachdem der Ausschuß den counted_ptr Vorschlag abgelehnt und nahm auto_ptr stattdessen wurde die Grundidee der counted_ptr auf Boost-wiederbelebt. Ich kann mich nicht daran erinnern, eine Diskussion über das Hinzufügen eines operator-> dazu gesehen zu haben, aber es "lebte" dort so lange, dass es durchaus möglich war, dass jemand es vorgeschlagen hätte, ohne dass ich es merkte.

+2

Aber so weit ich sehe, macht der vorgeschlagene 'operator->' genau das, was du beschreibst: konvertiere zu 'shared_ptr' und erlaube nur den Zugriff auf das Objekt, wenn das gelingt (andernfalls). Wie ist das eine schlechte Sache? –

+0

@MikeSeymour: Sie möchten die shared_ptr behalten und Methoden aufrufen, ohne die Synchronisationskosten zu bezahlen. –

+3

@AlexandreC .: Manchmal tun Sie, in diesem Fall ist manuelle Konvertierung noch verfügbar. Manchmal möchten Sie nur auf ein einzelnes Mitglied zugreifen. In diesem Fall ist die manuelle Konvertierung nur ein Rauschen, das der vorgeschlagene Operator verbessern kann. –

5

ich einen guten Grund zu geben einen Schuss nehmen würde, warum dies keine gute Idee ist:

Eines ist klar:

ptr->foo(); 
ptr->bar(); 

Das Problem hierbei ist, dass irgendwo zwischen den ersten und den zweiten call, ptr läuft möglicherweise ab, entweder durch einen anderen Thread (was eine Race-Bedingung wäre) oder durch einen Nebeneffekt des Aufrufs an foo.

Eine andere Sache ist die Symmetrie: Wenn ich einen Zeiger habe, erwarte ich Operatoren *, -> und eine implizite Umwandlung in einen booleschen Wert. Einige stimmen vielleicht nicht zu, aber die Operatoren * und -> fallen oft zusammen. Ich wäre überrascht, dass dies hier nicht der Fall ist.

Das heißt, mit 11 ++ C, es ist einfach zu einfach zu schreiben:

if (auto p = ptr.lock()) { 
    p->foo(); 
    p->bar(); 
} 

Zu wissen, dass ptr ein weak_ptr ist, ist die Bedeutung und das Verhalten des Codes ziemlich klar.

+0

Nach mehr Fragen, ich denke, Sie haben Recht mit Symmetrie. Mit operator-> würde weak_ptr eher wie ein tatsächlicher Zeiger aussehen, wenn ihm der einfachste Operator * fehlt. – Taylor

+0

Es ist mir auch eingefallen, dass dies ein guter Grund ist. Kurz gesagt, weak_ptr ist kein Zeiger, also sollte er sich nicht wie ein Zeiger verhalten müssen. Vielleicht wäre weak_ref eine bessere Wahl gewesen, aber der Begriff Referenz wird auch verwendet. –