2013-03-21 16 views
5

Kilka sposobów dodawania elementu do pojemnika z inteligentnymi wskaźnikami. Zastanawiam się, w którą stronę pójdziesz.Dodaj element do pojemnika z inteligentnymi wskaźnikami

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> 

}; 

osobiście pójść na Drogę 1. Wszelkie więcej korzyści na drodze 2 i 3 lub wad sposób 1, które powinny iść na 2 lub 3?

sftrabbit daje wiele dobrych punktów. W poniższym typowym przypadku. Jak korzystać z Way 2 lub 3, aby zrobić to z łatwością? Użytkownik używa okna dialogowego do wygenerowania nowego elementu pochodnego. Jest umieszczony na std::unique_ptr<DerivedItem> item. Po kliknięciu przycisku "OK" jest on dodawany do kontenera. Jeśli nie udało się dodać, wróć do okna dialogowego edycji.

Odpowiedz

6

I głosować na:

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

powodów:

  1. To wynika z podpisu funkcji, które klient musi przekazać własność obiektu do MyContainer. Jeśli zamiast tego wybierzesz opcję 1, nadal nie będzie jasne, czy klient powinien sam/sama, czy nie, czy też powinien przekazywać obiekt przydzielany dynamicznie.

  2. Klient jest zmuszony do jawnego przeniesienia prawa własności na std::move, jeśli już posiada obiekt zarządzany przez nazwanego std::unique_ptr. Nie przypadkowo stracą własność. Opcja 3 nie wyraża wyraźnie, że przejmie odpowiedzialność.

  3. Gdy mamy std::make_unique (N3588) metoda na dodanie elementu będzie:

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

    ten sposób unika się stosując new i poprawia bezpieczeństwo wyjątku w niektórych sytuacjach.

  4. Problem, który podałeś dla obiektów pochodnych, nie stanowi problemu. Otrzymasz błąd podczas kompilacji, jeśli zrobisz to niepoprawnie.

  5. Jeśli interfejs zmieni się na inny typ inteligentnego wskaźnika, klient będzie chciał wiedzieć, . Nie chcą kontynuować przekazywania przedmiotów, myśląc, że przekazują własność, jeśli w rzeczywistości ją udostępniają. Będą szczególnie chcieli wiedzieć, czy dzieje się odwrotnie.

+0

+1, zwłaszcza dla rozumu 2. – us2012

+0

Rozważmy przypadek. Użytkownik używa okna dialogowego do wygenerowania nowego elementu pochodnego. Jest umieszczony na 'std :: unique_ptr item'. Po kliknięciu przycisku "OK" jest on dodawany do kontenera. Jeśli nie udało się dodać, wróć do okna dialogowego edycji. Który sposób jest wygodniejszy? Dzięki. – user1899020

+0

@ user1899020 Trzymam się mojej odpowiedzi. Jest niezależny od tego, do czego dokładnie używasz "MyContainer". Po prostu zalecamy zezwolenie na propagowanie wyjątku, jeśli nie możesz dodać elementu "Przedmiot". Od tego zależy klient. –

2

Niestety, pierwsza droga poważnie zagraża bezpieczeństwu typu - wskazywałeś, że my sami mamy wady. Myślę, że te obawy przesłoniły wszelkie zalety tej metody.

W szczególności, potencjalny błąd drugiej metody przy korzystaniu z obiektu pochodnego jest wychwytywany podczas kompilacji, więc jest denerwujący, ale bezpieczny!

Zgadzam się z Twoją oceną, że to użycie powoduje wyciek szczegółów implementacyjnych, ale z mojego doświadczenia wynika, że ​​taki przeciek jest nieunikniony - Zgadzam się z sfrabbitem, że jest to w rzeczywistości szczegół, o którym musi wiedzieć użytkownik klasy.

1

Potraktuj to jako kolejne narzędzie w przyborniku:

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

ten łączy w sobie zalety Way 2 i 3. Drogi tj będzie przyjmować tylko rvalue unique_ptr s (jak 2), ale jeśli jest jakaś awaria dodanie go do pojemnika, może zachować prawo własności jak 3. Może być używany coś takiego:

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

Czy to samo co Way 2? Czy może to zrobić: 'std :: unique_ptr a (nowa pozycja); Dodaj (a); "jak Way 3? – user1899020

Powiązane problemy