2013-03-21 14 views
5

Diversi modi per aggiungere un elemento in un contenitore di puntatori intelligenti. Mi sto chiedendo in che direzione andrai.Aggiungere un elemento in un contenitore di puntatori intelligenti

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> 

}; 

io personalmente vado per strada 1. Qualsiasi più vantaggi per Way 2 e 3 o svantaggi di Via 1 che dovrei andare per 2 o 3?

sftrabbit fornisce molti buoni punti. Nel seguente caso comune. Come usare Way 2 o 3 per farlo facilmente? L'utente usa una finestra di dialogo per generare un nuovo oggetto derivato. È messo su std::unique_ptr<DerivedItem> item. Quando fai clic sul pulsante 'OK', viene aggiunto al contenitore. Se non è stato possibile aggiungere, tornare alla finestra di dialogo per una modifica.

risposta

6

Io voto per:

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

Motivi:

  1. E 'chiaro dalla firma della funzione che il cliente ha bisogno di passare la proprietà dell'oggetto al MyContainer. Se si sceglie invece l'opzione 1, non è ancora chiaro se il client debba o meno delete l'oggetto o anche se debba passare un oggetto allocato dinamicamente.

  2. Il client è costretto a trasferire esplicitamente la proprietà con std::move se ha già l'oggetto gestito da un oggetto denominato std::unique_ptr. Non perderanno accidentalmente la proprietà. L'opzione 3 non esprime chiaramente che ne assumerà la proprietà.

  3. Quando abbiamo std::make_unique (N3588), il metodo per aggiungere un elemento sarà:

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

    Questo evita l'impiego new e migliora la sicurezza eccezione in alcune situazioni.

  4. Il problema che hai fornito per gli oggetti derivati ​​non è davvero un problema. Avrai un errore in fase di compilazione se lo fai in modo errato.

  5. Se l'interfaccia cambia per utilizzare un diverso tipo di puntatore intelligente, il client sarà desidera sapere. Non vogliono continuare a passare oggetti pensando di passare la proprietà se in realtà lo condividono. Vogliono soprattutto sapere se succede il contrario.

+0

+1, in particolare per la ragione 2. – us2012

+0

Consideriamo un caso. L'utente usa una finestra di dialogo per generare un nuovo oggetto derivato. Si trova su 'std :: unique_ptr item'. Quando fai clic sul pulsante 'OK', viene aggiunto al contenitore. Se non è stato possibile aggiungere, tornare alla finestra di dialogo per una modifica. In che modo è più conveniente? Grazie. – user1899020

+0

@ user1899020 Mi sto attenendo alla mia risposta. È indipendente da cosa stai usando 'MyContainer' per. Ti raccomando di consentire la propagazione di un'eccezione se non puoi aggiungere l'elemento '. Spetta al cliente gestirlo. –

2

Purtroppo il primo modo compromette seriamente digitare la sicurezza - che avete fatto notare che il nostro se stessi in svantaggi. Penso che queste preoccupazioni stiano ignorando tutti i vantaggi che questo metodo potrebbe avere.

In particolare, il potenziale errore con il secondo metodo quando si utilizza un oggetto derivato viene catturato in fase di compilazione quindi è fastidioso, ma sicuro!

Sono d'accordo sulla tua valutazione secondo cui questo utilizzo perde i dettagli di implementazione ma nella mia esperienza tale fuoriuscita è inevitabile - Sono d'accordo con sfrabbit che questo è in realtà un dettaglio che l'utente della classe deve sapere.

1

considerare questo come un altro strumento nella casella degli strumenti:

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

Questo unisce i vantaggi della Way 2 e 3. Vale a dire Way sarà solo accettare rvalue unique_ptr s (come 2), ma se c'è qualche guasto in aggiunta al contenitore, si può mantenere la proprietà come 3. Ha potuto essere usato qualcosa come:

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

È uguale al modo 2? Può farlo: 'std :: unique_ptr a (nuovo elemento); Aggiungi (a); 'come Way 3? – user1899020