Considérez ce code:
#include <vector>
void Example()
{
std::vector<TCHAR*> list;
TCHAR* pLine = new TCHAR[20];
list.Push_back(pLine);
list.clear(); // is delete called here?
// is delete pLine; necessary?
}
Est-ce que list.clear () appelle delete sur chaque élément? C'est à dire. dois-je libérer la mémoire avant/après list.clear ()?
Non (vous devez faire la suppression vous-même à la fin comme vous le suggérez dans votre exemple car la destruction du pointeur chauve ne fait rien). Mais vous pouvez utiliser un pointeur intelligent boost [ou un autre idiome basé sur RAII] pour lui faire faire la bonne chose (auto_ptr
ne fonctionnerait pas correctement dans un conteneur car il a un comportement incompatible lors de la copie, etc.), mais assurez-vous de comprendre les pièges de ces pointeurs intelligents avant utilisation. (Comme le mentionne Benoit, dans ce cas, basic_string
est ce que vous cherchez vraiment ici.)
Cela dit, il est nécessaire de comprendre les pièges des pointeurs intelligents, les faire prendre implicitement en charge la gestion de la mémoire afin que vous n'ayez pas à le faire explicitement est beaucoup moins sujet aux erreurs.
EDIT: substantiellement révisé pour englober les éléments que Benoit a apportés dans sa réponse beaucoup plus approfondie, grâce aux fortes incitations de Earwicker et James Matta - merci de m'avoir poussé à faire preuve de diligence raisonnable à ce sujet!
std :: vector appelle le destructeur de chaque élément qu'il contient lorsque clear () est appelé. Dans votre cas particulier, il détruit le pointeur mais les objets restent.
Les pointeurs intelligents sont la bonne voie à suivre, mais soyez prudent. auto_ptr ne peut pas être utilisé dans les conteneurs std. boost :: scoped_ptr ne peut pas non plus. boost :: shared_ptr peut, mais cela ne fonctionnera pas dans votre cas car vous n'avez pas de pointeur sur un objet, vous utilisez en fait un tableau. La solution à votre problème est donc d'utiliser boost :: shared_array .
Mais je vous suggère d'utiliser std :: basic_string à la place, où vous n'aurez pas à vous occuper de la gestion de la mémoire, tout en bénéficiant des avantages de travailler avec une chaîne.
Vous pouvez simplement écrire une fonction de modèle simple qui fait cela pour vous:
template <class T>
void deleteInVector(vector<T*>* deleteme) {
while(!deleteme->empty()) {
delete deleteme->back();
deleteme->pop_back();
}
delete deleteme;
}
Peut-être que quelque chose ici est une mauvaise pratique, mais je ne pense pas. Cela me semble bien, même si les commentaires sont toujours agréables.
Voici une façon de dire que ce n'est pas le cas - essayez-le sur une classe qui n'est pas entièrement définie:
#include <vector>
class NotDefined;
void clearVector( std::vector<NotDefined*>& clearme )
{
clearme.clear(); // is delete called here?
}
Si cet extrait est compilé, il ne peut pas appeler le destructeur, car le destructeur n'est pas défini.
Nan. Cela ne fait pas cela car il n'y a aucune garantie que vous n'utilisez le pointeur nulle part ailleurs. Si ce n'était pas une variable pointeur, cela les libérerait (en appelant le destructeur)
Vous pourriez également être en mesure d'utiliser la Boost Pointer Container Library . Non spécifiquement recommandé ici (encore une fois, car vous utilisez des tableaux au lieu d'objets uniques, bien que std::string
s'en occuperait), mais c'est une bibliothèque utile et peu connue qui résout le problème mentionné dans le titre.