Mon PP m'y a de nouveau fait penser, finalement j'ai pas mal fait évoluer la solution et j'ai un truc qui marche vraiment pas trop mal. J'ai implémenté les casts implicites correctement et en fin de compte je pense que c'est un bon compromis pour une lib (graphique dans mon cas) :
- Les références peuvent être créées implicitement, mais dans ce cas elles ne possèdent pas l'objet (ce n'est rien de plus qu'un pointeur au sens C++, avec la même syntaxe)
- Quand on initialise une référence si on veut qu'elle possède l'objet il faut appeler mkref. On n'a besoin de faire ça qu'avec un new.
- Les fonctions qui supportent la gestion de mémoire demandent des ref<Type> et stockent ça comme membres
- L'utilisateur final peut travailler avec des ref ou pas, c'est transparent. S'il veut qu'un objet créé soit automatiquement delete'é lorsqu'il n'est plus référencé, il appelle juste mkref et se sert du pointeur comme habituellement. Les ref's transformées en pointeur sont valides tant que la ref est référencée quelque part, ainsi comme pour la création classique d'objets c'est celui qui crée l'objet qui gère le cycle de vie. Ca signifie que si la référence est un membre de classe, on aura le même comportement que si un delete était appelé dans le destructeur.
void fonctionDeLaLib(ref<Truc> truc) {
}
ref<Truc> autreFonctionDeLaLib() {
return mkref(new Truc());
}
void fonctionAMoi(Truc *t) {
}
void main() {
Truc *sansGestionDeMemoire = new Truc();
ref<Truc> avecGestionDeMemoire = mkref(new Truc());
fonctionDeLaLib(sansGestionDeMemoire);
fonctionDeLaLib(avecGestionDeMemoire);
fonctionDeLaLib(mkref(new Truc());
delete sansGestionDeMemoire;
avecGestionDeMemoire = autreFonctionDeLaLib();
fonctionAMoi(avecGestionDeMemoire);
// Libère le contenu actuel de avecGestionDeMemoire et assigne un pointeur non géré
avecGestionDeMemoire = new Truc();
delete (Truc*) avecGestionDeMemoire;
}