it-swarm.com.de

size () Vs empty () in vector - warum wird empty () bevorzugt?

Während des Debuggens habe ich die STL vector :: empty () -Implementierung gesehen:

bool empty() const
        {return (size() == 0); }

Ich glaube, wann immer wir die Leere des Vektors untersuchen, wird immer empfohlen, übergroße Leerzeichen () zu verwenden. Aber angesichts dieser Implementierung frage ich mich, was der Vorteil davon ist. Stattdessen entsteht beim Aufruf von empty ein Funktionsaufruf-Overhead, da er intern size () == 0 aufruft.

Ich dachte, dass empty () im Falle von list hilfreich sein könnte, da size () nicht die konstante Zeit in list garantiert. Um meine Annahme zu überprüfen, überprüfte ich die Listenimplementierung und fand überraschenderweise die gleiche Implementierung auch in der Liste.

return (size() == 0);

Ich bin jetzt etwas verwirrt. Wenn leer intern size () verwendet, warum sollten wir dann leer statt size () bevorzugen?

31
aJ.

Sie müssen die Bedingung jedes Mal aufschreiben, wenn Sie size() verwenden. Es ist bequem, empty() zu verwenden. Dies ist natürlich nur möglich, wenn Sie die Container nicht wechseln. Wie bereits erwähnt, ist es Sache der Implementierung, size() in empty() zu verwenden oder nicht. Der Standard garantiert jedoch Folgendes: empty() ist eine zeitlich konstante Operation für alle Standardcontainer.

24
dirkgently

Wenn Sie von std :: vector zu std :: list oder einem anderen Container wechseln, kann dies anders sein.

Zum Beispiel nehmen einige Implementierungen von std::list::sizeO(n) und nicht O(1) an.

41
Artyom

Nun, wie Sie sagen, das ist nur ein Implementierungsdetail. std::list kann entweder mit einer gespeicherten Größe (konstante Zeit size() aber lineare Zeit splice()) oder ohne (konstante Zeit splice() aber lineare Zeit size()) implementiert werden. Wenn Sie empty() verwenden, vermeiden Sie das Setzen auf ein Implementierungsdetail, wenn Sie die Größe nicht kennen müssen.

9

Nach dem Standard sollte empty () bevorzugt werden, da es unabhängig vom Containertyp eine konstante zeitliche Komplexität aufweist.

In C++ 03 Standard, Kapitel 23.1, Tabelle 65: Containeranforderungen

Operation:   empty()
Return_type: convertible to bool
Semantics:   equivalent to size()==0
Complexity:  constant

Es scheint, als hätten Sie in Ihrer STL-Implementierung die Semantik als echte Implementierung verwendet, ohne die Komplexitätsanforderungen zu beachten, oder size () ist eine konstante Zeit in der Implementierung (gespeichertes Feld).

Wenn size () keine konstante Zeit ist, wenden Sie sich an Ihren Händler, wenn std :: list <> :: empty () die Standardanforderungen für Container nicht erfüllt.

Erstens macht die Verwendung einer Funktion namens empty(), wenn Sie wissen möchten, ob etwas leer ist, den Code besser lesbar, und Sie müssen sich keine Gedanken über Implementierungsdetails machen. Dies bedeutet auch, dass Ihr Code einfacher an andere Containertypen mit anderen Merkmalen angepasst werden kann.

Zweitens ist das nur eine STL-Implementierung. Mein GNU C++ sieht so aus:

bool
empty() const
{ return begin() == end(); }

Dies führt schließlich zu einem Zeigervergleich, während die Verwendung von size () zu einer Subtraktion führen würde (in dieser Implementierung).

Drittens ist es nicht sehr wahrscheinlich, dass ein zusätzlicher Funktionsaufruf anfällt, da die Funktion empty()- wahrscheinlich (in beiden Implementierungen) eingebettet ist.

5
gnud

empty () hat O(1) Implementierungen für ALLE Containerklassen. size () kann für einige Container nur O(n) -Implementierungen bereitstellen; Deshalb wird empty () bevorzugt.

4
paxos1977

Zusätzlich zu den oben genannten Gründen ist es wahrscheinlich klarer als foo.size () == 0 und/oder!

1
Alex

Abgesehen von dem Lesbarkeitspunkt, der sehr gültig ist, haben Sie lediglich die Artefakte einer bestimmten Implementierung erlebt, nicht die einzig möglichen.

Das heißt, es gibt keinen Grund oder die Forderung, dass empty () sowohl im Vektor- als auch im Listenfall in Bezug auf size () oder in der Tat in einem anderen Container implementiert werden muss. Wenn es leistungsfähigere Alternativen gibt, sollten diese verwendet werden, es sei denn, die Autoren der Bibliothek sind inkompetent oder eher faul.

In Bezug auf die Liste und die O (1) -Einheit von size () oder deren Fehlen sollten Sie berücksichtigen, dass die Liste entweder size () als O(1) oder Splice () implementiert. , aber nicht beides (das Nachdenken über den Grund ist eine interessante Übung.) In Ihrem Fall könnte die Bibliothek, die Sie untersucht haben, size () als O(1) implementiert haben (in diesem Fall wäre splice () der Fall) O(n)) und könnte daher empty () in Bezug auf size () implementieren, ohne die Leistung zu beeinträchtigen, andernfalls wäre dies eine wirklich schlechte Bibliothek.

0
Ash

Verwenden Sie lieber empty () als size (), da jeder Container die empty () - Implementierung auf andere Weise implementieren kann, um den Vorgang mit konstanter Zeit zu erhalten.

beispiel:

vektor implementiert als: bool empty () const {// test, wenn die Sequenz leer ist return (size () == 0); }

liste der Geräte als:

        bool empty() const
    {   // test if sequence is empty
    return (_Mysize == 0);
    }
0
Jakkula Vamsi