> 5- on ne met jamais new et delete dans une même fonction
Pourquoi donc ?
Si j'avais une variable locale, trop grosse pour être mise dans la pile, j'utiliserai une procédure avec un new (ou alors un constructeur de l'objet qui alloue la variable) au début, je ferais le calcule sur cette variable, et je la détruirai ensuite (ou alors j'appellerai le destructeur de l'objet, qui déléterait cet objet). Ce n'est pas comme ça qu'il est souhaitable de faire ?
Je suppose qu'il dit cela a propos des exceptions. Si tu as :
void foo() {
auto p = new int;
... bla bla bla
delete p;
}
Si une exception est lancée, tu auras une fuite mémoire.
C'est possible de catch les exceptions :
void foo() {
auto p = new int;
try {
... bla bla bla
}
catch(...) {
delete p;
}
delete p;
}
Mais cela devient très très vite impossible à gérer si tu as plusieurs pointeurs (puisqu'il faut un try-catch pour chaque new, puisque new peut lancer une exception).
La seule solution clean exception safe, c'est de faire comme il dit : utiliser les constructeurs/destructeurs ou une classe RAII existante.
Mon interprétation de son point est qu'il faille dans l'ordre
1- préférer mettre la variable sur la pile
2- et (deux) si ce n'est vraiment pas possible parce qu'elle est trop grosse (je n'en connais pas de la sorte qui ne soient pas des tableaux qui ne peuvent être résolus avec des vecteurs), `auto p = make_unique....`
Ce qui est bien, c'est que l'on a déjà répondu pour moi
Je n'ai donc rien à rajouter à ce qu'on dit gbdivers et lmghs, car ils ont déjà tout dit
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
> 5- on ne met jamais new et delete dans une même fonction
Pourquoi donc ?
Si j'avais une variable locale, trop grosse pour être mise dans la pile, j'utiliserai une procédure avec un new (ou alors un constructeur de l'objet qui alloue la variable) au début, je ferais le calcule sur cette variable, et je la détruirai ensuite (ou alors j'appellerai le destructeur de l'objet, qui déléterait cet objet). Ce n'est pas comme ça qu'il est souhaitable de faire ?
Il va falloir y aller pour faire sauter la pile avec une variable trop « grosse ». Dans tous les cas, tu n'auras jamais besoin de new ou delete sauf raison valable.
En fait, le message, c'est : "pas de new" et "pas de delete" tout court !
Si possible...
Maintenant, ben, quand tu as des types polymorphes à cause d'un héritage publique, que le type de tes instances est défini à l'exécution et que tu veux gérer tes instances comme s'il s'agissait d'instances de la classe de base, l'idéal serait -- bien sur -- d'utiliser des pointeurs intelligents (qui, au final, vont cacher new et delete dans des fonctions -- voire des foncteurs -- séparés ) ou ... dans certaines circonstances... de faire tes propres classes RAII.
A priori, tu as largement assez d'outils pour n'avoir aucun besoin d'appeler new et delete par toi-même. Maintenant, sachant que rien n'est jamais gravé dans le marbre, va savoir si les a priori sont bons et valables dans ta situation particulière ?
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
Pour new et delete, je ne vois pas trop de cas d'utilisation qui ne pourraient pas être remplacé par unique_ptr.
Mais on peut avec des cas d'utilisation avec malloc/free, des buffers non initialise 2, des fonctions systèmes ou de libs (en général pour des optimisations).
Et il ne faut pas oublier que l'initialisation ne concerne pas que l'allocation mémoire, mais également tout ce qui est nécessaire pour avoir un objet valide et tout ce qui est nécessaire pour libérer correctement.
Le point super important dans l'implémentation du RAII, c'est de respecter le principe de responsabilité unique. Si tu essaies de faire trop de chose dans les constructeurs et destructeurs, tu peux perdre l'intérêt du RAII.
class MyFakeRAII {
public:
MyFakeRAII() {
m_p1 = new P;
m_p2 = new P; // peut lancer une exception !
doSomethingToInit(); // peut lancer une exception !
}
~MyFakeRAII() {
doSomethingToRelease();
delete m_p1;
delete m_p2;
}
private:
P* m_p1 = nullptr;
P* m_p2 = nullptr;
};
Ce code n'est pas safe. Il ne faut pas hésiter à découper les classes.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Discord NaN. Mon site.
git is great because Linus did it, mercurial is better because he didn't.
Discord NaN. Mon site.