2010-07-11 7 views
7

Sagen wir, ich habe ein std::list von class T ‚s:std :: list <std :: unique_ptr <T>>: passing es um

std::list<T> l; 

Wenn es in Funktionen vorbei, würde ich eine Referenz verwenden:

someFunction(std::list<T> &l) 

Was ist der beste Weg, um (std::list von unique_ptr s) (die Elemente) zu umgehen?

std::list< std::unique_ptr<T> > l; 

So:

someFunction(std::unique_ptr<T> ptr) 

Oder diese:

someFunction(T* ptr) 

Oder diese:

someFunction(T &ref) 

Und was wie würde ich es nennen die std::list ‚s mit back() Funktion zum Beispiel? Dies sind IMHO alle "Art" Äquivalent, aber ich bin sicher, dass ich hier etwas vermisse.

Dank

Antwort

7

Um der Beste zu schlechter:

  1. Funktion (const T &);
  2. someFunction (T &);
  3. someFunction (const std :: eindeutiges_ptr <T> &);
  4. someFunction (std :: unique_ptr <T> &);

Die erste ist die beste, weil es nicht das Objekt, um es nicht ändern und es wird ganz gleich mit dem Objekt arbeiten, wie Sie es zugewiesen haben (zum Beispiel, könnten Sie wechseln ohne Probleme Shared_ptr).

Nummer zwei funktioniert auch unabhängig davon, welchen Smart Pointer Sie verwenden; Es wird jedoch davon ausgegangen, dass Sie das Objekt ändern können und wann immer Sie etwas const machen können, sollten Sie.

Die Nummern 3 und 4 erlauben beide, dass das Objekt, auf das hingewiesen wird, mutiert wird; # 3 lässt jedoch nicht zu, dass der intelligente Zeiger geändert wird, während Nummer 4 dies tut. Beide haben den Nachteil, dass sie die Verwendung von unique_ptr erzwingen, während die beiden darüber unabhängig von der Smart-Pointer-Klasse funktionieren würden.

Das Übergeben eines unique_ptr nach Wert, wie Sie in einigen der anderen Beispiele haben, ist keine Option; Ein unique_ptr soll einzigartig sein. Wenn Sie es kopieren, sollten Sie shared_ptr verwenden.

Für die ersten beiden, wenn Sie es auf das Ergebnis zurück() geltend gemacht, würde es wie folgt aussehen:

someFunction(*(lst.back())); // dereference lst.back() before passing it in. 

Für die beiden letzteren, wenn Sie es auf dem resut von hinten() aufgerufen, es würde so aussehen:

someFunction(lst.back()); // pass the smart pointer, not the object to 
          // which the smart pointer currently points. 
+0

Danke für die eingehende Erklärung. Daher ist keine spezielle Semantik für intelligente Zeiger erforderlich (außer der Dereferenzierung). Ich wusste von dem 'const'-Zeug, aber in diesem Fall muss ich das übergebene' T'-Objekt modifizieren. – rubenvb

1

do nicht Pass unique_ptr nach Wert, alle zunächst nicht ohne std::move kompilieren und wenn Siestd::move Gebrauch machen es wird die leeren Wert, den Sie in Ihrem list gespeichert haben, und Sie können nicht mehr darauf zugreifen.

Dies liegt daran, unique_ptr nicht kopierbar ist, ist es nicht eine Kopie Konstruktor des Typs hat unique_ptr::unique_ptr(const unique_ptr<T>& other) stattdessen hat sie nur einen Zug Konstruktor (unique_ptr::unique_ptr(unique_ptr<T>&& source)).

0

unique_ptr und auch Klassen/Instanzen enthalten unique_ptr können (und andere Behälter) in std :: Liste verwendet werden, vorausgesetzt, dass sie bewegen Konstruktorclass_name(class_name &&) definiert haben (die unique_ptr, hat natürlich).

Wenn Sie um diese Elemente passieren, du bist immer in Bewegung (und nicht kopieren), um sie, so dass Sie immer std :: move() auf lvalues, wie in
my_list.push_back(std::move(my_element));
dies macht sichtbar, dass Sie Übergabe (= Verschieben) des Elements in die Liste, und dass my_element nach dieser Operation "leer" (wie leer unique_ptr) ist.

Beispiel:

typedef std::unique_ptr<uint8_t[]> data_ptr; 

class data_holder 
{ 
private: 
    int something_about_data; 
    data_ptr data; 
public: 
    data_holder(data_ptr && _data) 
     : data(std::move(_data)) 
    {} 

    // hey compiler, please generate a default move constructor for me 
    // despite of present destructor 
    data_holder(data_holder &&) = default; 

    ~data_holder() 
    { 
     // ... 
    } 

    bool is_empty() const { return ! bool(data); } 
} 

// ... 
{ 
    // ... 
    data_holder the_element(data_ptr(new uint8_t[DATA_SIZE])); 

    // move the_element into the_list 
    the_list.push_back(std::move(the_element)); 
    if (the_element.is_empty()) 
     std::cerr << "data_holder 'the_element' is now empty!" << std::endl; 
    // ... 
} 
Verwandte Themen