En effet je n'y ai pas pensé... Par exemple pour l'opérateur -> j'ai donc une seule fonction :Citation:
Envoyé par Médinoc
Les premiers tests ont l'air de marcher, c'est correct?Code:T * const operator -> () const;
Version imprimable
En effet je n'y ai pas pensé... Par exemple pour l'opérateur -> j'ai donc une seule fonction :Citation:
Envoyé par Médinoc
Les premiers tests ont l'air de marcher, c'est correct?Code:T * const operator -> () const;
C'est simple (oublie les considérations théoriques sur l'exception safety); le code suivant ne doit pas causer de fuite de mémoire, quoi qu'il advienne :
Oui, mais pourquoi ne pas trouver attraper toutes les exceptions avec catch(...)?Code:CSmartPointer<T> p (new T);
Tu peux aussi utiliser une "function-try-block" :
La function-try-block d'un constructeur englobe l'initialisation des membres, il correspond à une portée extérieure. Il ne faut donc surtout pas se référer aux membres de l'objet dans le bloc catch :Code:
1
2
3
4
5
6 CSmartPointer(T *p_) try : p(p_), pr(new int(1)) { } catch(...) { delete p_; }
Comme c'est un constructeur, atteindre la fin du bloc catch (le "}" fermant) relance l'exception (tout comme "throw;").
- certains n'ont pas été construits parce qu'une exception a interrompu l'exécution de la liste d'initialisation,
- les autres ont été détruits avant d'entrer dans le bloc catch
Sur une implémentation des exceptions à base de tables, le cout en temps d'exécution est nul. La taille de l'exécutable va très légèrement augmenter.
Euh... sans doute parce que je ne connaissait pas tout ça :D, en tout cas merci c'est toujours bon à savoir.Citation:
Envoyé par corrector
Si si, je viens de me relire c'était le sens de ma question, mais ce n'était pas voulu (:oops:) je voulais dire : "Je l'utilise pour supprimer m_Pointer si il est différent de NULL et le réinitialiser à NULL". Et puis au risque de ne toujours pas être clair voila la définition :Citation:
Ce code est parfaitement valide (et inutile, évidemment).
(Mais je ne suis pas sûr si c'était le sens de ta question.)
NOTE : mon SAFE_DELETE ne serait pas très "safe" si il ne désallouait que les pointeurs NULL :mouarf:Code:#define SAFE_DELETE(x) if(x) {delete x; x=0;}
NOTE2 : Encore une fois je tiens à remercier tout le monde pour les réponses apportées, ainsi que de m'avoir aidé à mieux comprendre tout ça! (surtout que je suis parfois à peine têtu) :merci:
Encore une erreur, je vais battre le record en un topic :roll:. Je suppose qu'UNE PARTIE du problème peut se résoudre comme ça :En revanche il reste toujours un problème mais je ne vois pas comment le régler :Code:#define SAFE_DELETE(x) { if(x) {delete x; x=0;} }
Code:
1
2 if (cond) SAFE_DELETE(p); // Compile
Est-ce vraiment nécessaire de pouvoir compiler ce code sachant que :Code:
1
2
3
4 if (cond) SAFE_DELETE(p); else // Erreur : "instruction else sans if correspondant non conforme" ...
Et puis sachant aussi que le ";" est inutile?Code:
1
2
3
4
5
6 if (cond) { SAFE_DELETE(p); } else // Ok ...
EDIT : J'ai oublié, éventuellement une fonction inlinée pourrais remplacé le define, mais est-ce vraiment utile... ?
C'est là où je voulais en venir : pourquoi s'embêter avec les macros et les problèmes associés, dont tu as eu un aperçu, alors que tu peux écrire une vraie fonction normale, inline pour éviter tout surcout. (Mais, par rapport à delete, un appel de fonction n'est pas bien lourd.)
Dans ce cas précis, quelles sont les problèmes associés que l'ont n'aurait pas avec une fonction, exemple :Citation:
Envoyé par corrector
et :Code:
1
2
3
4
5 if (cond) SAFE_DELETE(p); else // Macro : Erreur // Fonction : Ok ...
Mis à part le fait que les macros "semblent" être de moins en mois appréciées quand elle peuvent être évitées (enfin je dis ça d'après ce que j'en ai lu..), dans ce cas c'est bien une question de choix non?Code:
1
2
3
4
5 if (cond) SAFE_DELETE(p) else // Macro : Ok // Fonction : Erreur ...
Ce que j'ai montré précédemment, déjà. (Il y en d'autres, essaie de les trouver.)
Ce n'est pas que les macros sont de moins en moins appréciées, elles sont détestées (en plus, le préprocesseur est un très mauvais langage de macro : peu puissant, difficile à définir et à implémenter, en plus il est mal intégré au langage).
On les utilise quand on n'a pas mieux.
Quand une fonction fait l'affaire, utiliser une macro est considéré comme une erreur grossière.
Oui, c'est bien l'usage d'un constructeur de conversion ("converting constructor") :
Comme il n'y a pas de mot-clef "implicit", l'absence d'explicit sur un constructeur à un argument peut être un simple oublie, sans un commentaire comment savoir.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 class A { public: explicit A (int); A (const char*); // non-explicit }; void foo (A); int main() { foo (1); // erreur foo ("1"); // OK, équivaut à : foo (A("1")); A a = 2; // erreur A a = "2"; // OK, équivaut à : A a = A("2"); }
Le risque de la conversion implicite, c'est qu'elle est implicite (n'est-ce pas), alors tu peux l'invoquer par erreur, et, par exemple, donner à un smart pointer la propriété d'un pointeur, sans le vouloir.
La crainte avec les conversions implicites c'est de les faire sans le vouloir, et qu'un code incorrect compile grâce à elles. En pratique, il faut analyser l'opportunité de déclarer des conversions implicites au cas par cas.
Ouha... quelle influence j'ai!
Essaie:
Qui devrait résoudre les problèmes de 'if' imbriqués et le problème du ';'.Code:
1
2#define SAFE_DELETE(p) do { if(x) { delete (x); (x)=0; } } while (false)
Ceci dit, la meilleure manière de le faire reste:
Autre chose, cette fonction n'est pas un safe_delete mais un delete_to_null. Rien à voir (au niveau du nom et de la fonction réalisée).Code:
1
2
3
4
5
6
7 namespace { template <class T> void safe_delete(T*& p) { if (p) { delete p; p = NULL; } } }
Merci pour ces précisions, comme conseillé par corrector, j'ai déjà créé une fonction :J'aurais quand même une ou deux questions par rapport à ton code, pourquoi utiliser un namespace sans nom? Cela change-t-il quelques choses? Aussi je ne vois pas la différence entre "T *&" et "T *"... :aie: ?Code:
1
2
3
4
5
6
7
8
9 template <class T> inline void SafeDelete(T *ptr) { if(ptr!=0) { delete ptr; ptr=0; } }
C'est simple: Sans le &, ton ptr=0 ne sert à rien.Citation:
Aussi je ne vois pas la différence entre "T *&" et "T *"... ?
En effet ça a du sens, merci pour la précision :DDonc si j'ai bien compris, dans mon cas c'est à éviter, puisque je souhaite pouvoir réutiliser cette fonction dans d'autre projets(/fichiers).Et je vais aussi la renommer :mouarf:, à la base j'ai donné ce nom car j'ai vu cette fonction(Macro) plusieurs fois sous ce nom (:oops:) mais en effet il ne semble pas y avoir de bonnes raisons (enfin à ma connaissance)...Citation:
Autre chose, cette fonction n'est pas un safe_delete mais un delete_to_null. Rien à voir (au niveau du nom et de la fonction réalisée).
Encore merci à tous pour tous ces précieux conseils :D