2013-03-21 8 views
5

Mehrere Möglichkeiten zum Hinzufügen eines Elements in einem Container mit Smartpointern. Ich frage mich, auf welche Art Sie gehen werden.Hinzufügen eines Elements in einem Container mit Smartpointern

class MyContainer 
{ 
private: 
    std::vector<std::unique_ptr<Item>> mItems; 

public: 
    bool Add(Item* item); 
    // This is Way 1 
    // 
    // Advantages: 
    // - Easy to add derived items, such as Add(new DerivedItem); 
    // - No interface change if smart pointer type changes to such as shared_ptr; 
    // 
    // Disadvantages: 
    // - Don't explicitly show the item to add must be allocated on heap; 
    // - If failed to add, user has to delete the item. 

    bool Add(std::unique_ptr<Item> item); 
    // This is Way 2 
    // Disadvantages and advantages are reversed from Way 1. 
    // Such as to add derived item, Add(std::unique_ptr<Item>(new DerivedItem)); 
    //             | 
    //        easy to write DerivedItem here for an error 

    bool Add(std::unique_ptr<Item>& item); 
    // This is Way 3 
    // Similar to Way 2, but when failed to add, item still exist if it is a 
    // reference of outer unique_ptr<Item> 

}; 

ich persönlich für Weg gehen 1. Jede weitere Vorteile für Way 2 und 3 oder Nachteile Way 1, die ich für 2 oder 3 gehen sollte?

sfstrabbit gibt viele gute Punkte. Im folgenden häufigen Fall. Wie benutze ich Way 2 oder 3 um es einfach zu machen? Benutzer verwendet einen Dialog, um ein neues abgeleitetes Element zu generieren. Es ist auf std::unique_ptr<DerivedItem> item gesetzt. Wenn Sie auf 'OK' klicken, wird es dem Container hinzugefügt. Wenn das Hinzufügen fehlgeschlagen ist, kehren Sie zum Dialogfeld für eine Bearbeitung zurück.

Antwort

6

Ich stimme für:

bool Add(std::unique_ptr<Item> item); 

Gründe:

  1. Es ist klar, aus der Funktion Unterschrift, dass der Kunde das Eigentum an dem Objekt zu dem MyContainer passieren muss. Wenn Sie stattdessen die Option 1 wählen, ist es immer noch nicht klar, ob der Client das Objekt selbst oder nicht delete sein soll oder ob er ein dynamisch zugewiesenes Objekt übergeben soll.

  2. Der Client muss das Eigentumsrecht explizit mit std::move übertragen, wenn das Objekt bereits von einem benannten std::unique_ptr verwaltet wird. Sie werden nicht versehentlich das Eigentum verlieren. In Option 3 wird nicht klar zum Ausdruck gebracht, dass sie Eigentum übernehmen wird.

  3. Wenn wir std::make_unique (N3588) haben, wobei das Verfahren ein Element für das Hinzufügen wird:

    container.Add(std::make_unique<Item>()); 
    

    Dies vermeidet new mit und verbessert Ausnahme Sicherheit in einigen Situationen.

  4. Das Problem, das Sie für abgeleitete Objekte angegeben haben, ist nicht wirklich ein Problem. Sie erhalten einen Fehler bei der Kompilierung, wenn Sie es falsch machen.

  5. Wenn sich die Schnittstelle ändert, um einen anderen Typ von Smartpointer zu verwenden, muss der Client wissen. Sie wollen nicht weiter Objekte weitergeben, die denken, dass sie das Eigentum weitergeben, wenn sie es in Wirklichkeit teilen. Sie wollen vor allem wissen, ob das Gegenteil passiert.

+0

+1, vor allem für die Vernunft 2. – us2012

+0

Betrachten wir einen Fall. Benutzer verwendet einen Dialog, um ein neues abgeleitetes Element zu generieren. Es wird auf 'std :: unique_ptr item' gesetzt. Wenn Sie auf 'OK' klicken, wird es dem Container hinzugefügt. Wenn das Hinzufügen fehlgeschlagen ist, kehren Sie zum Dialogfeld für eine Bearbeitung zurück. Welcher Weg ist bequemer? Vielen Dank. – user1899020

+0

@ user1899020 Ich bleibe bei meiner Antwort. Es ist unabhängig davon, wofür Sie 'MyContainer' genau verwenden. Ich empfehle nur, dass Sie eine Ausnahme propagieren lassen, wenn Sie das 'Item' nicht hinzufügen können. Es liegt an dem Kunden, damit umzugehen. –

2

Leider ist der erste Weg, eine schwere Beeinträchtigung Sicherheit geben - Sie wies darauf haben, dass unsere selbst in den Nachteilen. Ich denke, dass diese Bedenken alle Vorteile überschatten, die diese Methode haben könnte.

Insbesondere der mögliche Fehler mit der zweiten Methode bei der Verwendung eines abgeleiteten Objekts wird zur Kompilierzeit gefangen, so dass es ärgerlich ist, aber sicher!

ich über Ihre Einschätzung einig, dass diese Nutzung Lecks Implementierungsdetails aber nach meiner Erfahrung eine solche Leckage ist unvermeidlich - ich mit sfrabbit einig, dass dies tatsächlich ein Detail, dass der Benutzer der Klasse darüber wissen muss.

1

Betrachten Sie dies als ein weiteres Werkzeug in der Toolbox:

bool Add(std::unique_ptr<Item>&& item); 

Diese vereint die Vorteile von Way 2 und Way 3. D. h es wird nur rvalue unique_ptr s (wie 2) annehmen, aber wenn es irgendein Fehler ist es zu dem Behälter in hinzufügen, können sie das Eigentum behalten wie 3. etwas ähnliches verwendet werden könne:

void 
foo(MyContainer& c) 
{ 
    std::unique_ptr<Item> p = get_Item(); 
    try 
    { 
     c.Add(std::move(p)); 
    } 
    catch (...) 
    { 
     log_error_wtih(*p); 
    } 
} 
+0

Ist es das gleiche wie Way 2? Kann es das tun? 'Std :: unique_ptr a (neues Item); Addiere (a): "Wie Way 3? – user1899020