Pointeurs ou seulement les objets ?
En C++, il n'est pas possible de mettre des références dans un tableau. On peut faire un tableau de pointeurs, mais je préférerais toujours un conteneur et des objets réels plutôt que des pointeurs parce que.. :
- Il n'y a pas de risque de fuite, la sécurité exceptionnelle est plus facile à gérer.
- Ce n'est pas moins d'espace - si vous stockez un tableau de pointeurs, vous avez besoin de la mémoire pour l'objet plus la mémoire pour un pointeur.
Les seules fois où je préconiserais de mettre des pointeurs (ou des pointeurs intelligents, ce serait mieux) dans un conteneur (ou un tableau si vous devez le faire), c'est lorsque votre objet n'est pas constructible et assignable par copie (une exigence pour les conteneurs, les pointeurs répondent toujours à cette exigence) ou lorsque vous avez besoin qu'ils soient polymorphes. Par exemple
#include <vector>
struct foo {
virtual void it() {}
};
struct bar : public foo {
int a;
virtual void it() {}
};
int main() {
std::vector<foo> v;
v.push_back(bar()); // not doing what you expected! (the temporary bar gets "made into" a foo before storing as a foo and your vector doesn't get a bar added)
std::vector<foo*> v2;
v2.push_back(new bar()); // Fine
}
Si vous voulez suivre cette voie conteneurs de pointeurs d'appoint peuvent être intéressantes car elles font tout le travail à votre place.
Retrait de tableaux ou de conteneurs.
Affectation NULL
ne réduit pas le nombre de pointeurs dans votre conteneur/ tableau, (il ne gère pas la fonction delete
soit), la taille reste la même mais il y a maintenant des pointeurs que vous ne pouvez pas déréférencer légalement. Cela rend le reste de votre code plus complexe sous la forme d'instructions if supplémentaires et interdit des choses comme :
// need to go out of our way to make sure there's no NULL here
std::for_each(v2.begin(),v2.end(), std::mem_fun(&foo::it));
Je n'aime pas du tout l'idée d'autoriser NULL
dans des séquences de pointeurs en général, car vous finissez rapidement par enterrer tout le travail réel dans une séquence d'instructions conditionnelles. L'alternative est la suivante std::vector
fournit une erase
qui prend un itérateur afin que vous puissiez écrire :
v2.erase(v2.begin());
pour supprimer le premier ou le v2.begin()+1
pour le second. Il n'y a pas de méthode simple pour "effacer le nième élément" sur std::vector
en raison de la complexité temporelle - si vous effectuez beaucoup d'effacements, il existe d'autres conteneurs qui pourraient être plus appropriés.
Pour un tableau, vous pouvez simuler l'effacement avec :
#include <utility>
#include <iterator>
#include <algorithm>
#include <iostream>
int main() {
int arr[] = {1,2,3,4};
int len = sizeof(arr)/sizeof(*arr);
std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// remove 2nd element, without preserving order:
std::swap(arr[1], arr[len-1]);
len -= 1;
std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// and again, first element:
std::swap(arr[0], arr[len-1]);
len -= 1;
std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
Le maintien de l'ordre nécessite une série de mélanges au lieu d'un seul échange, ce qui illustre bien la complexité de l'effacement des données. std::vector
les visages. Bien sûr, en faisant cela, vous venez de réinventer une roue assez grande, avec beaucoup moins d'utilité et de souplesse qu'un conteneur de bibliothèque standard ne le ferait pour vous gratuitement !