2013-08-27 10 views
6

Wenn Sie kein dynamisches Wachstum benötigen und die Größe des Puffers zur Kompilierzeit nicht kennen, wann sollte unique_ptr<int[]> anstelle von vector<int> verwendet werden, wenn überhaupt?unique_ptr <int[]> oder Vektor <int>?

Gibt es einen erheblichen Leistungsverlust bei der Verwendung von vector anstelle von unique_ptr?

+10

Warum nicht ein std :: array? – Bart

+5

@Bart Er muss den einmal zugewiesenen Speicher nicht vergrößern, das bedeutet nicht, dass er die Größe zur Kompilierzeit kennt. – Praetorian

+0

@Bart Ich habe die Frage aktualisiert, um davon auszugehen, dass die Größe des Puffers zur Kompilierzeit nicht bekannt ist. – huitlarc

Antwort

4

Es gibt keinen Leistungsverlust std::vector vs. std::unique_ptr<int[]> in Verwendung. Die Alternativen sind jedoch nicht genau gleichwertig, da der Vektor gewachsen werden kann und der Zeiger nicht kann (dies kann sein und ein Vorteil oder ein Nachteil, ist der Vektor versehentlich gewachsen?)

Es gibt andere Unterschiede, wie die Tatsache, dass die Werte werden in der std::vector initialisiert, aber sie werden nicht sein, wenn Sie new das Array (es sei denn, Sie verwenden Wert-Initialisierung ...).

Am Ende des Tages würde ich persönlich für std::vector<> entscheiden, aber ich Code immer noch in C++ 03 ohne std::unique_ptr.

+0

Vergessen wir auch nicht, dass es bei der 'unique_ptr'-Methode keine Größenangaben gibt. –

4

C++ 14 führt zu diesem Zweck std :: dynarray ein.

nun zwischen diesen beiden Konstruktionen:

  1. auto buffer = std::make_unique<int[]>(someCount);
  2. auto buffer = std::vector<int>(someCount, someValue);

Die erste gibt Ihnen eine nicht initialisierte Array von int aber die zweite initialisiert es mit einem Wert (0, wenn nicht liefern). Also, wenn Sie initialisiert den Speicher nicht sein müssen, weil Sie es irgendwie später mit etwas komplexer als std::fill überschrieben, 1 wählen, wenn nicht, wählen 2.

+6

C++, was bist du geworden ... – GManNickG

+4

Ich dachte "dynarray" wurde eingeführt, um C++ - Programmierer zu trollen. –

+0

@Mystical Die Geschichte hinter "Dynarray" ist subtiler als ein einfacher Troll. Es erfordert nicht so viel Geschick, ein grundlegendes "Dynarray" als einen festen "Vektor" mit einer standardmäßigen dynamischen Zuweisung zu schreiben. Aber das wahre Geheimnis dieses Objekts liegt darin, den Compiler entscheiden zu lassen, wo der Speicher zugewiesen wird, er kann sich auf dem Heap befinden, aber er kann sich auf dem Stapel befinden. Und das ist auch mit C++ 11 einfach unmöglich. – galop1n

3

std::vector speichert die Länge sowohl der Größe der Variablen als auch der Größe der zugewiesenen Daten zusammen mit dem Zeiger auf die Daten selbst. std::unique_ptr speichert nur den Zeiger, so dass es einen kleinen Gewinn bei der Verwendung von std::unique_ptr geben kann.

Niemand hat noch erwähnt, dass der Vektor Iteratoren und Funktion wie und size() bietet, wo nicht eindeutig ptr nicht. Also, wenn Iteratoren benötigt werden, verwenden std::vector

1

Objective-Teil:

Nein, es sollte wohl kein signifikanter Unterschied in der Leistung zwischen den beiden sein (obwohl ich es auf die Umsetzung annehmen hängt, und Sie sollten messen, wenn es wichtig ist) .

Subjektive Teil:

std::vector wird Ihnen eine bekannte Schnittstelle mit .size() und .at() und Iteratoren geben, die gut mit allen möglichen anderen Code spielen. Die Verwendung von std::unique_ptr gibt Ihnen eine primitivere Schnittstelle und ermöglicht es Ihnen, Details (wie die Größe) separat zu verfolgen. Abgesehen von anderen Einschränkungen würde ich daher std::vector bevorzugen.

6

Wenn Sie in einer Position sind, in der vector<int> sogar eine Möglichkeit ist, möchten Sie wahrscheinlich damit gehen, außer in extremen und seltenen Fällen.Und selbst dann könnte ein benutzerdefinierter Typ anstelle von unique_ptr<int[]> die beste Antwort sein.

Also was zum Teufel ist unique_ptr<int[]> gut für? :-)

unique_ptr<T[]> wirklich glänzt in zwei Fällen:

1. Sie benötigen einen malloc/free Ressource von einer Legacy-Funktion zu handhaben und Sie würden es in einer modernen Ausnahme sichere Art zu tun:

void 
foo() 
{ 
    std::unique_ptr<char[], void(*)(void*)> p(strdup("some text"), std::free); 
    for (unsigned i = 0; p[i]; ++i) 
     std::cout << p[i]; 
    std::cout << '\n'; 
} 

2. Sie hat Bedarf vorübergehend eine neue [] Ressource zu sichern, bevor es auf einem anderen Inhaber übertragen:

class X 
{ 
    int* data_; 
    std::string name_; 

    static void validate(const std::string& nm); 
public: 
    ~X() {delete [] data_;} 

    X(int* data, const std::string& name_of_data) 
     : data_(nullptr), 
      name_() 
    { 
     std::unique_ptr<int[]> hold(data); // noexcept 
     name_ = name_of_data;    // might throw 
     validate(name_);     // might throw 
     data_ = hold.release();    // noexcept 
    } 
}; 

Im obigen Szenario besitzt X den übergebenen Zeiger, unabhängig davon, ob der Konstruktor erfolgreich ist oder nicht. Dieses spezielle Beispiel setzt einen noexcept Standardkonstruktor für std::string voraus, der nicht vorgeschrieben ist. Jedoch:

  1. Dieser Punkt ist verallgemeinerbar für Umstände, die std::string nicht betreffen.
  2. Ein std::string Standardkonstruktor, der wirft, ist lahm.
Verwandte Themen