81 votes

QVector vs QList

J'ai une liste d'entiers sur laquelle j'ai besoin d'itérer, mais un tableau est inadéquat. Quelles sont les différences entre vectors y lists et y a-t-il quelque chose que je dois savoir avant de choisir un type ?

Pour être clair, j'ai lu la documentation de QT mais c'est tout ce que je sais :

QList<T> , QLinkedList<T> y QVector<T> fournissent une fonctionnalité similaire. En voici un aperçu :

  • Dans la plupart des cas, QList est la bonne classe à utiliser. Son API basée sur l'index est plus pratique que QLinkedList's basée sur des itérateurs, et elle est généralement plus rapide que les QVector en raison de la manière dont il stocke ses éléments en mémoire. Il s'étend également à moins de code dans votre exécutable.
  • Si vous avez besoin d'une vraie liste chaînée, avec des garanties d'insertions en temps constant au milieu de la liste et des itérateurs vers les éléments plutôt que des index, utilisez QLinkedList .
  • Si vous souhaitez que les éléments occupent des positions de mémoire adjacentes, utilisez la fonction QVector .

125voto

Dennis Zickefoose Points 6659

QVector est en grande partie analogue à std::vector comme vous pouvez le deviner d'après son nom. QList est plus proche de boost::ptr_deque malgré l'association apparente avec std::list . Il ne stocke pas directement les objets, mais plutôt des pointeurs vers eux. Vous bénéficiez de tous les avantages des insertions rapides aux deux extrémités, et les réallocations impliquent le brassage des pointeurs au lieu des constructeurs de copie, mais vous perdez la localité spatiale d'un objet réel. std::deque o std::vector et gagner beaucoup d'allocations de tas. Il y a une certaine prise de décision pour éviter les allocations de tas pour les petits objets, regagnant la localité spatiale, mais d'après ce que j'ai compris, cela ne s'applique qu'aux choses plus petites qu'un an. int .

QLinkedList est analogue à std::list et en a tous les inconvénients. D'une manière générale, ce devrait être votre dernier choix de conteneur.

La bibliothèque QT favorise fortement l'utilisation de la fonction QList Par conséquent, les privilégier dans votre propre code peut parfois vous éviter des ennuis inutiles. L'utilisation supplémentaire du tas et le positionnement aléatoire des données réelles peuvent théoriquement nuire dans certaines circonstances, mais sont souvent imperceptibles. Je suggère donc d'utiliser QList jusqu'à ce que le profilage suggère de passer à un QVector . Si vous pensez que l'allocation contiguë est importante [lire : vous vous interfacez avec du code qui s'attend à une allocation contiguë], il est préférable d'utiliser une allocation contiguë. T[] au lieu d'un QList<T> ] cela peut également être une raison de commencer par QVector dès le départ.


Si vous posez des questions sur les conteneurs en général, et que vous avez juste utilisé les documents QT comme référence, alors les informations ci-dessus sont moins utiles.

Un site std::vector est un tableau que vous pouvez redimensionner. Tous les éléments sont stockés les uns à côté des autres, et vous pouvez accéder rapidement aux éléments individuels. L'inconvénient est que les insertions ne sont efficaces qu'à une extrémité. Si vous placez un élément au milieu ou au début, vous devez copier les autres objets pour faire de la place. En notation big-oh, l'insertion à la fin est O(1), l'insertion partout ailleurs est O(N), et l'accès aléatoire est O(1).

Un site std::deque est similaire, mais ne garantit pas que les objets sont stockés les uns à côté des autres, et permet à l'insertion aux deux extrémités d'être O(1). Elle nécessite également l'allocation de plus petits morceaux de mémoire à la fois, ce qui peut parfois être important. L'accès aléatoire est de O(1) et l'insertion au milieu est de O(N), comme dans le cas d'un vector . La localisation spatiale est pire que std::vector mais les objets ont tendance à être regroupés, ce qui présente certains avantages.

Un site std::list est une liste chaînée. Parmi les trois conteneurs séquentiels standard, c'est celui qui nécessite le plus de mémoire, mais il permet une insertion rapide partout... à condition que vous sachiez à l'avance où vous devez insérer. Elle n'offre pas d'accès aléatoire aux éléments individuels, il faut donc itérer en O(N). Mais une fois là, l'insertion réelle est O(1). Le plus grand avantage de std::list c'est que vous pouvez les assembler rapidement... si vous déplacez une gamme entière de valeurs vers un autre endroit... std::list l'opération entière est O(1). Il est également beaucoup plus difficile d'invalider les références dans la liste, ce qui peut parfois être important.

En règle générale, je préfère std::deque a std::vector sauf si je dois être capable de passer les données à une bibliothèque qui attend un tableau brut. std::vector est garanti contigu, donc &v[0] travaille à cette fin. Je ne me souviens pas de la dernière fois où j'ai utilisé un std::list mais c'était presque certainement parce que j'avais besoin d'une garantie plus forte sur la validité des références.

0 votes

Pour info, std::deque a d'assez bonnes garanties sur les références. Les itérateurs sont facilement invalidés, mais les pointeurs sur les membres sont assez robustes aux opérations sur la dequeue.

0 votes

Excellente réponse. Mais j'ai une question supplémentaire : Qu'est-ce qui est le plus rapide à itérer ? J'ai un ensemble d'objets, ils ne sont pas vraiment insérés ou supprimés souvent, mais j'ai besoin d'itérer sur les objets aussi vite que possible. Qu'est-ce qui est le plus rapide ?

0 votes

Bonne information. J'ai trouvé la déclaration suivante très utile... "La bibliothèque QT favorise fortement l'utilisation des objets QList". Dans mon cas d'utilisation, je traite avec un QTableWidget, qui aime QList et QListString. Par conséquent, laissez votre cas d'utilisation dicter votre décision entre QVector et QList.

13voto

Naszta Points 4322

Sur QVector est similaire à std::vector . QLinkedList est similaire à std::list . QList est un vecteur basé sur l'index, mais la position mémoire n'est pas garantie (comme std::deque ).

3voto

antitrust Points 4853

De la doc QtList :

  • QList à utiliser dans la plupart des cas. Pour les structures comportant un millier d'éléments, permet une insertion efficace au milieu, et fournit un accès indexé. prepend() y append() très rapide puisque la mémoire est pré-allouée aux deux extrémités du tableau interne. QList<T> est un tableau de pointeurs de type T. Si T est un pointeur ou un pointeur de type Qt shared-like, l'objet est stocké directement dans le tableau

  • QVector d'être préféré dans le cas de beaucoup de append() o insert() de nouveaux éléments dont la taille est supérieure à celle d'un pointeur depuis QVector alloue la mémoire pour ses éléments en une seule allocation de tas. Pour QList L'insertion ou l'ajout d'un nouvel élément nécessite l'allocation de la mémoire du nouvel élément sur le tas. En bref, si vous voulez que les éléments occupent des positions mémoire adjacentes, ou si vos éléments sont plus grands qu'un pointeur et que vous voulez éviter la surcharge de l'allocation individuelle sur le tas au moment de l'insertion, utilisez alors QVector .

-2voto

Nick Points 616

QVector est comme un tableau qui peut changer de taille (augmenter ou diminuer), mais il s'accompagne de lourdes transactions, de calculs et de temps.

Par exemple, si vous voulez ajouter un élément, un nouveau tableau est créé, tous les éléments sont copiés dans le nouveau tableau, le nouvel élément est ajouté à la fin, et l'ancien tableau est supprimé. Et vice versa pour supprimer également.

Cependant, QLinkedList fonctionne avec des pointeurs. Ainsi, lorsqu'un nouvel élément est créé, un nouvel espace mémoire est alloué et lié au seul morceau de mémoire. Comme il fonctionne avec des pointeurs, il est plus rapide et efficace.

Si vous avez une liste d'articles dont vous ne pensez pas que la taille va beaucoup changer, QVector est probablement bon, mais généralement QLinkedList est utilisé dans la plupart des cas.

3 votes

1 : QVector ne s'accompagne pas de transactions lourdes comme vous le prétendez, car il pré-alloue et possède une bonne stratégie de croissance/réduction pour l'ajout et le retrait. La pré-allocation et l'insertion nécessitent en effet de déplacer des plages de données, mais comme elles sont continues en mémoire, cela se fait très rapidement (le cache peut bien fonctionner avec des données continues, contrairement à des morceaux de tas éparpillés comme avec QList). Votre deuxième affirmation selon laquelle QLinkedList est utilisée dans la plupart des cas est tout simplement fausse. Elle est très rarement utilisée. Vous pourriez la confondre avec QList ?

-5voto

Comme vous std::array ou std::hash en c++11 ? Il n'y a pas de limitation sur le type de template dans ce dialecte !!! Comme en c# par exemple... ou d'autres langages ! L'idée des chaînes brutes est bonne si elle fonctionne... La bonne idée est de faire remonter les constructeurs parents dans la classe enfant. Les templates variadiques ne sont pas débuggeables comme cela se produit...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X