Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Qt] Pourquoi des pointeurs ?

Sujet résolu
12 mai 2010 à 0:43:28

Citation : Freedom

std::vector<obj*> est un fournisseur préféré potentiel de la méthode ~obj() en tant que classe d'une variable de obj, en tant que tel (et par la loi de Demeter), je peus utiliser son protocole, en particulier le message erase(), begin() et end().


Le problème n'est pas que tu puisses ou non utiliser le vector<obj*> et ses méthodes dans obj, mais que tu puisses accéder au vector de parent à partir de this. En gros, tu peux jouer avec parent, mais pas avec les jouets de parent ;)

Il y a aussi un principe de simplification, et parent->collector->erase c'est compliqué, même si tu le décomposes sur plusieurs lignes. Alors que parent->removeChild avec removeChild qui fait collector->erase c'est simple. Avec le principe KISS tu devrais également faire une méthode séparée pour effacer tous les enfants, même si elle reste private ou protected.
En plus, il y a des chances que tu ais besoin par la suite d'une méthode removeChild en dehors du destructeur (pas YAGNI donc). Et garder les 2 codes enfreindrait la règle DRY :)
  • Partager sur Facebook
  • Partager sur Twitter
12 mai 2010 à 0:50:00

Citation : alexisdm

Citation : Freedom

std::vector<obj*> est un fournisseur préféré potentiel de la méthode ~obj() en tant que classe d'une variable de obj, en tant que tel (et par la loi de Demeter), je peus utiliser son protocole, en particulier le message erase(), begin() et end().


Le problème n'est pas que tu puisses ou non utiliser le vector<obj*> et ses méthodes dans obj, mais que tu puisses accéder au vector de parent à partir de this. En gros, tu peux jouer avec parent, mais pas avec les jouets de parent ;)

Il y a aussi un principe de simplification, et parent->collector->erase c'est compliqué, même si tu le décomposes sur plusieurs lignes. Alors que parent->removeChild avec removeChild qui fait collector->erase c'est simple. Avec le principe KISS tu devrais également faire une méthode séparée pour effacer tous les enfants, même si elle reste private ou protected.
En plus, il y a des chances que tu ais besoin par la suite d'une méthode removeChild en dehors du destructeur (pas YAGNI donc). Et garder les 2 codes enfreindrait la règle DRY :)


Je t'ai fait une demonstration formelle de la validité de mon code par rapport à LoD, elle est pas contestable en disant "tu peut jouer avec parent" qui est une vulagisation de LoD. (quand je dis je peus, ce n'est pas au sens technique, mais bien au sens de la validité de l'architecture du code). (Lis le lien que j'ai donné si tu as des doutes sur ma démonstration et les termes que j'ai utilisé)
Les autres arguments, je suis d'accord.
  • Partager sur Facebook
  • Partager sur Twitter
FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
12 mai 2010 à 1:25:41

Citation : Freedom

Je t'ai fait une demonstration formelle de la validité de mon code par rapport à LoD, elle est pas contestable en disant "tu peut jouer avec parent" qui est une vulagisation de LoD. (quand je dis je peus, ce n'est pas au sens technique, mais bien au sens de la validité de l'architecture du code). (Lis le lien que j'ai donné si tu as des doutes sur ma démonstration et les termes que j'ai utilisé)


Ce lien n'a qu'une définition incomplète, si tu lis le papier d'origine tu verras que ça s'applique aussi aux objets et pas juste aux classes.
  • Partager sur Facebook
  • Partager sur Twitter
12 mai 2010 à 2:09:37

Citation : alexisdm

Citation : Freedom

Je t'ai fait une demonstration formelle de la validité de mon code par rapport à LoD, elle est pas contestable en disant "tu peut jouer avec parent" qui est une vulagisation de LoD. (quand je dis je peus, ce n'est pas au sens technique, mais bien au sens de la validité de l'architecture du code). (Lis le lien que j'ai donné si tu as des doutes sur ma démonstration et les termes que j'ai utilisé)


Ce lien n'a qu'une définition incomplète, si tu lis le papier d'origine tu verras que ça s'applique aussi aux objets et pas juste aux classes.


Je viens relire le papier, et en effet il y a un version objet, mais le papier précise clairement que celle-ci sert de "guide" pour la verification de la loi, car la version classe est plus difficile à vérifier (le papier parle de verification à la compilation), la version exact étant bien celle avec les classes (il y a même une seconde distinction au sein de cette définition). (Le lien est donc parfaitement complet)

Citation : LoD - Fin de la première section

So far we discussed the class version of the Law of Demeter which can be
enforced at compile-time. The price we pay for compile-time enforceability
is that some programs which violate the ``spirit'' of the Law will pass
the test or that some programs which follow
the ``spirit'' of the Law will be rejected.
Therefore we present now the object version of the Law which expresses
the spirit of the Law and which serves as a conceptual guideline to be
approximated in programming.


NB: Je suis loin d'être parfaitement anglophone, mais il ne me semble pas avoir fait un contre-sens, si c'est le cas, Mea culpa.
  • Partager sur Facebook
  • Partager sur Twitter
FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
12 mai 2010 à 8:54:16

Citation : Freedom

Je viens relire le papier, et en effet il y a un version objet, mais le papier précise clairement que celle-ci sert de "guide" pour la verification de la loi, car la version classe est plus difficile à vérifier (le papier parle de verification à la compilation), la version exact étant bien celle avec les classes (il y a même une seconde distinction au sein de cette définition). (Le lien est donc parfaitement complet)


Au contraire, la version avec les classes est la seule qu'il est possible d'imposer à la compilation (="which can be enforced at compile-time").
A la fin la partie suivant, il est indiqué plus clairement:

Citation : LoD

The object version of the Law expresses what we really want, but unfortunately it is hard to enforce at compile-time.

Soit: "La version objet de la Loi exprime ce que nous voulons réellement, mais malheureusement, il est difficile de l'imposer à la compilation".
  • Partager sur Facebook
  • Partager sur Twitter
12 mai 2010 à 12:26:58

Citation : alexisdm

possible d'imposer à la compilation (="which can be enforced at compile-time").
A la fin la partie suivant, il est indiqué plus clairement:

Citation : LoD

The object version of the Law expresses what we really want, but unfortunately it is hard to enforce at compile-time.

Soit: "La version objet de la Loi exprime ce que nous voulons réellement, mais malheureusement, il est difficile de l'imposer à la compilation".


Je reconnait avoir lu cette phrase, mais je la trouve en opposition avec (où alors j'ai mal compris, ce qui est possible aussi)

Citation : LoD


the object version [...] which serves as a conceptual guideline to be approximated in programming.


Quoiqu'il en soit, j'aurait du séparer pour respecter les autres points que tu as relever plus haut, mais je ne pense vraiment pas que LoD soit vraiment violer ici.
  • Partager sur Facebook
  • Partager sur Twitter
FaQ : Fr | En 1 2 | C++11 | Template || Blog : Deloget | C++|Boost--Dev | C++Next | GotW || Installer Boost
12 mai 2010 à 12:41:17

Citation : Freedom

Citation : alexisdm

<citation nom="LoD">
the object version [...] which serves as a conceptual guideline to be approximated in programming.


Ça veut pourtant dire, et ça n'est pas une interprétation de ma part, que c'est la version objet qu'il faut essayer de suivre en premier lieu, parce que c'est cette version qui est à la base de la Loi de Déméter, mais que le compilateur ne peut vérifier que la version avec les classes (grâce en C++ aux sections private/protected, et entre autre, à l'absence d'accesseurs via des analyseurs de métrique de code).
  • Partager sur Facebook
  • Partager sur Twitter
13 décembre 2022 à 14:03:18

Bonjour,

Je vais surement me mettre tous le monde a dos (ou pas) car je suis vais être partiellement d'accord avec tous le monde.

Je dis pas avoir la réponse, mais je vais exposer mon avis sur la question.

Pour moi il n'y a aucune obligation a utiliser des pointeurs avec des QObject, sa dépend comment on les utilise (et certains ne laissent pas trop le choix)

Oui Qt a son propre mécanisme de suppression de ses enfants, mais il n'est actif que si on donne un parent a la création de l'objet.

Si on reprends ce très bon exemple :

#include <QObject>
 
int main()
{
   QObject enfant;
   QObject parent;
   enfant.setParent(&parent);
    
}

il suffit de faire ça :

#include <QObject>
 
int main()
{
   QObject enfant;
   QObject parent;
    
}
Et finalement on aura plus de soucis a la destruction. 
Donc c'est surtout au dev de connaitre et bien comprendre le mécanisme Parent/enfant de Qt, et de l'utiliser ou non.
Du coup mettre des pointeurs partout systématiquement, je suis contre, sa reste dangereux, imaginons cet exemple :
#include <QObject>
 
int main()
{
   QObject* enfant = new QObject();
   QObject* parent = new QObject();
   enfant = new QObject();
}
L'exemple est trop simple pour que sa pose réellement problème, mais la vous aurez une fuite mémoire. Comme je disais sa reste un exemple très simple. Si vous utilisez des pointeurs et ne spécifiez pas le parent, le mécanisme Qt ne fonctionne pas. Et c'est source d'erreur. 
En général tous les constructeurs des classes dérivés QObject sont écris comme tel :
MyQObject::MyQObject(QObject parent = nullptr) : QObject(parent)
{

}

Et on l'appelle comme ça par exemple :

MyQObject(this);

Mais si on oublie de fournir un QObject parent ? Ou si dans le constructeur on oublie d'appeler le constructeur parent (en général QObject) ?

Et bien la le mécanisme de suppression ne fonctionne plus. 

Dans la mesure ou il n'est pas absolument nécessaire et en plus pas forcément maitrisé par tous le monde et dur de s'assurer qu'il soit correctement appliqué. Je préfère avoir pour règle qu'il ne soit pas utiliser sauf si nécessaire.

Les cas de nécessité sont assez rare.

Soit parce que vous avez besoin de créer l'objet dynamiquement et qu'en suite vous ne le manipulerez plus du tout (donc a quoi bon le stocker dans un attribut ?).

Ou Alors car vous utilisez un autre dérivé QObject qui a besoin de son parent pour fonctionner (QState il me semble par exemple). 

Et quand vous utilisez le mécanisme QT, ne surtout pas utiliser des smart pointer, ils partageront la responsabilité de la vie du pointeur avec le mécanisme QT et cela fera forcément des étincelles (déjà vu du code comme ça qui plantait systématiquement a la fermeture de l'appli). J'ai enlevé les smart pointer et les pointeurs tout court et l'utilisation des parents/enfants de Qt. Le besoin d'utiliser des pointeurs n'existaient pas, le dev avait cru bien faire en voyant sur internet qu'on utilise des allocations dynamique pour QT, cumulé a l'autre conseil d'utiliser des smartpointer pour chaque allocation dynamique.

Séparément les deux conseils fonctionnent bien, mais une fois cumulé non. Donc je préfère conseiller d'utiliser les pointeurs que si absolument nécessaire, et quand c'est le cas de bien maitriser le cycle de vie de son instance (soit via des smart pointer, soit via le mécanisme Qt, soit ...).

Voila pour mon humble avis sur la question.

  • Partager sur Facebook
  • Partager sur Twitter
13 décembre 2022 à 14:18:25

> Voila pour mon humble avis sur la question.

en réponse au dernier message qui était de 2010.

  • Partager sur Facebook
  • Partager sur Twitter
13 décembre 2022 à 18:17:20

Surtout que ca était dit par Freedom que les pointeurs sont pas obligatoires. Et pleins de code d'exemple donnés n'utilisent pas de pointeurs.

Quand a la phase "Les cas de nécessité sont assez rare", je ne suis pas trop d'accord. Il arrive tres souvent qu'on n'a pas le choix avec Qt. Par exemple, dans les codes donnés, on utilise des fonctions comme "setCentralWidget", "setLayout" et "addWidget", qui ajoutent le parent. Et les 2 premiers codes donnés en exemple ne peuvent pas être fait sans pointeur. Plus généralement, quand on écrit une classe QWidget qui contient des membres QWidget, on est souvent obligé d'utiliser des pointeurs (ce qui arrive souvent)

  • Partager sur Facebook
  • Partager sur Twitter
14 décembre 2022 à 7:48:10

Bonjour,

Le message qui suit est une réponse automatique activée par un membre de l'équipe. Les réponses automatiques leur permettent d'éviter d'avoir à répéter de nombreuses fois la même chose, ce qui leur fait gagner du temps et leur permet de s'occuper des sujets qui méritent plus d'attention.
Nous sommes néanmoins ouverts et si vous avez une question ou une remarque, n'hésitez pas à contacter la personne en question par Message Privé.

Pour plus d'informations, nous vous invitons à lire les règles générales du forum

Déterrage

Citation des règles générales du forum :

Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.

Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre.
En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.

Au lieu de déterrer un sujet il est préférable :

  • soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
  • soit de créer un nouveau sujet décrivant votre propre contexte
  • ne pas répondre à un déterrage et le signaler à la modération

Je ferme ce sujet. En cas de désaccord, me contacter par MP.

  • Partager sur Facebook
  • Partager sur Twitter

Pas d'aide concernant le code par MP, le forum est là pour ça :)