wake-up-neo.com

"Richtige" Möglichkeit, ein std :: vector-Objekt freizugeben

Die erste Lösung ist:

std::vector<int> *vec = new std::vector<int>;
assert(vec != NULL);
// ...
delete vec;

Eine Alternative ist:

std::vector<int> v;
//...
vec.clear();
vec.swap(std::vector<int>(vec));

Die zweite Lösung ist ein bisschen ein Trick - was ist der "richtige" Weg, um es zu tun?

Aktualisieren:

Ich bin mir bewusst, dass der Destruktor aufgerufen wird, sobald er vom Stapel ist. Ich war neugierig auf andere Methoden.

32
Jacob

Die einfachste und zuverlässigste Methode, einen Vektor freizugeben, besteht darin, ihn auf dem Stack zu deklarieren und einfach nichts zu tun.

void Foo() {
  std::vector<int> v;
  ...
}

C++ garantiert, dass der Destruktor von v aufgerufen wird, wenn die Methode ausgeführt wird. Der Destruktor von std::vector sorgt dafür, dass der zugewiesene Speicher freigegeben wird. Solange der T-Typ von vector<T> über eine korrekte C++ - Deallocation-Semantik verfügt, ist alles in Ordnung. 

34
JaredPar

Der einfachste Weg, den gesamten Speicher in einem Vektor freizugeben, ohne das Vektorobjekt selbst zu zerstören, ist

vec = std::vector<int>();

Ihre zweite Variante hat den gleichen Effekt, sie springt jedoch durch weitere Reifen. Der Trick "Kopieren und Austauschen" hebt die zusätzliche Kapazität im Vektor auf und kann nützlich sein, wenn er einige Daten enthält, die Sie behalten möchten. Wenn keine Daten vorhanden sind, müssen Sie weder kopieren noch austauschen.

15
Mike Seymour
std::vector<int> vi;
/*Push lots of stuff into the vector*/

// clean it up in C++03
// no need to clear() first
std::vector<int>().swap(vi);

// clean it up in C++0x
// not a one liner, but much more idiomatic
vi.clear();
vi.shrink_to_fit();
12
deft_code

Ich stimme mit Mike Seymour überein. Probieren Sie dies aus, dann werden Sie feststellen, dass das letzte funktioniert

const int big_size = 10000;
vector<double> v( big_size );
cout << "Before clearing, the capacity of the vector is "
  << v.capacity() << " and its size is " << v.size();
v.clear();
cout << "\nAfter clearing, the capacity of the vector is "
  << v.capacity() << " and its size is " << v.size();
vector<double>().swap( v );

cout << "\nAfter swapping, the capacity of the vector is "
  << v.capacity() << " and its size is " << v.size();

vector<double> v1( big_size );
v1 = vector<double>();
cout << "\n After vector<double>();, the capacity of the vector is "
  << v1.capacity() << " and its size is " << v1.size();
3
Sam

Verwenden Sie keine Speicherzuordnungsfunktionen, es sei denn, Sie müssen dies wirklich tun. Wenn Ihre Klasse immer einen Vektor benötigt, fügen Sie einfach das Element std :: vector direkt hinzu. Hier müssen Sie keine Speicherzuordnung vornehmen.

In den Fällen, in denen Sie den dynamischen Vektor benötigen, ist das Zuordnen und Löschen wie in Ihrem ersten Beispiel 100% korrekt.

Im zweiten Beispiel wird der Aufruf von std :: swap strikt nicht benötigt, da die clear-Methode den Vektor löscht und ihn leer macht. Ein mögliches Problem besteht darin, dass es keine Garantie gibt, dass der Vektor den Speicher tatsächlich freigibt und an das Betriebssystem (oder die Laufzeit) zurückgibt. Der Vektor behält möglicherweise den zugewiesenen Speicher für den Fall, dass Sie den Vektor unmittelbar nach dem Löschen füllen. Der Aufruf von std :: swap kann ein Trick sein, um den Vektor zu zwingen, seine internen Daten freizugeben. Es kann jedoch nicht garantiert werden, dass dies tatsächlich geschieht.

1
Patrick

Ich vermute hier, dass Sie einen Vektor haben, der vorübergehend eine große Datenmenge enthält. Nachdem der Vektor gelöscht wurde, nimmt er immer noch den gesamten Speicher auf. Sie möchten diesen Speicher freigeben, nachdem Sie damit fertig sind, aber die Funktion/das Objekt, mit dem Sie arbeiten, ist noch nicht abgeschlossen.

Lösungen in abnehmender Reihenfolge der Erwünschtheit:

  1. Überarbeiten Sie den Code so, dass sich der Vektor, der den Code verwendet, in seinem eigenen Block/seiner Funktion/seinem eigenen Objekt befindet, sodass er auf natürliche Weise zerstört wird
  2. Verwenden Sie den Swap-Trick. Auf diese Weise müssen Sie sich nicht darum kümmern, dass der Vektor unter allen Umständen freigegeben wird. Ihre Lebensdauer hängt von dem Objekt/der Funktion ab, in der Sie sich befinden.
  3. neu/lösche den Vektor. Dadurch wird etwas mehr Speicherplatz als bei der vorherigen Methode freigegeben, es ist jedoch schwieriger, sicherzustellen, dass kein Speicherplatz verloren geht.

Der einzige technische Unterschied zwischen Tauschen und Löschen besteht darin, dass der Basisvektor selbst nicht zerstört wird. Dies ist ein kleiner Aufwand und es lohnt sich nicht, sich darüber Sorgen zu machen (solange Sie den Vektor letztendlich zerstören)

Die größere Überlegung ist, dass es einfacher ist, korrekten Code zu schreiben, und ich glaube, Swap gewinnt beim Löschen an Stelle, ist aber schlimmer, als den Vektor an einen anderen Ort zu verschieben.

1
Winston Ewert

Wenn Sie den Vektor nur aus dem Geltungsbereich herausnehmen lassen, wird er sich ohne zusätzliche Arbeit entsprechend aufräumen. Wenn der Vektor eine Membervariable einer Klasse ist und der Inhalt freigegeben werden soll, bevor der Besitzer des Objekts zerstört wird, rufen Sie einfach vec.clear () auf.

Wenn Sie den Vektor beibehalten, den Speicher jedoch freigeben möchten, der den Inhalt enthält, wird vec.swap(std::vector<int>()); dies tun. Es ist nicht erforderlich, das temporäre Element in das Original zu kopieren, es sei denn, vec enthält Elemente, die Sie behalten möchten, und Sie möchten nur den zugewiesenen Speicher auf eine Größe reduzieren, die der aktuellen Größe () entspricht.

0
Alan

Falls der Vektor wirklich auf dem Heap sein muss, vergessen Sie nicht:

std::auto_ptr<std::vector<int> > vec(new std::vector<int>);

besonders nützlich bei Code wie:

std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());
0
Graphics Noob

Dies ist kein gültiger Vergleich, da sich die Beispiele auf verschiedene Arten von Objekten beziehen: dynamische Dauer und lokale Dauer. Sie können den Destruktor OR mit dem Swap-Trick (aka shrink_to_fit) mit einem der beiden aufrufen. Die Art von right hängt davon ab, ob Sie das Vektorobjekt benötigen oder nicht.

Es kann beispielsweise erforderlich sein, dass sie persistent ist wenn es Verweise oder Hinweise darauf gibt die gültig bleiben müssen. In diesem Fall ist das Verkleinern der einzige Weg, unabhängig von der Zuweisung.

0
Cubbi

Ich bin nicht sicher, warum Ihr zweites Beispiel einen Kopierkonstruktor für den temporären statt einen Standardkonstruktor verwendet. Das würde Ihnen die .clear() Codezeile ersparen.

Sie können dieses generisch für jedes Objekt festlegen, auch wenn es sich nicht um einen Container handelt. Ich gehe davon aus, dass sich std :: swap darauf spezialisiert hat, vector :: swap aufzurufen.

template<typename T>
void ResetToDefault(T & value)
{
    std::swap(T(), value);
}

std::vector<int> vec;  
//...  
ResetToDefault(vec);
0
Mark Ransom

Löschen hebt den Speicher auf, der Speicher ist dann für das nächste Objekt frei, aber der Vektor ist verschwunden. 

Der zweite Trick gibt überschüssigen Speicher frei, lässt den Vektor jedoch intakt, aber leer.

0
Martin Beckett

Obwohl beide zu funktionieren scheinen, sehe ich keinen Grund, nicht einfach delete auf dem Zeiger aufzurufen. Der Vektor sollte einen Destruktor haben, der alles andere behandelt. 

0
Ben313