Bonjour !
Voilà je maintiens un programme assez important en C++ dont 99.9% du code est très portable (je veux dire par là qu'il ne dépend que de la librairie Standard C++, ce qui inclut la STL).
Le 0.1% non-portable concerne une toute petite classe qui permet d'écrire des données vers une sorte de périphérique.
Cette classe était définie jusqu'à présent sous Linux un peu de cette façon :
Je dois réimplementer cette classe sous Windows, et ce qu'elle doit faire est tellement simple que l'api native Win32 suffit parfaitement à mes besoins.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 // OutputDevice.h class OutputDevice { public: // .... Diverses méthodes, constructeurs & destructeur // void Write (const std::string& out); private: int m_fd; // Descripteur de fichier };
Mon problème, c'est que pour obtenir une classe similaire je dois faire ça :
HANDLE est un type définit par Windows.h (ou un header inclut par ce dernier), et inclure Windows.h pollue le namespace global d'un tas de trucs qui rendent le reste du code (censé être portable) pas forcément évident à maintenir. Parmis ces nuisances figurent énormément de macros comme min()/max() et un tas de noms de fonctions comme CreateFile() qui est implémenté comme une macro pour CreateFileA() et CreateFileW().
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 #include <windows.h> class OutputDevice { public: // .... Diverses méthodes, constructeurs & destructeur // void Write (const std::string& out); private: HANDLE m_fd; // Descripteur de fichier, version Windows };
Je pourrais tout à fait utiliser un pImpl (pointeur sur implémentation) et donc avoir une autre classe qui se charge d'allouer un objet opaque contenant un HANDLE:
Mais mince quoi !! ça voudrait dire qu'à chaque fois que j'instancie cette classe OutputDevice, je force une allocation mémoire pour stocker une variable HANDLE de 4 octets ???? Pfff .... C'est pas vraiment un problème pour les performances mais je trouve ça lourd.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class OutputDevice { class Impl; public: // .... Diverses méthodes, constructeurs & destructeur // void Write (const std::string& out); private: std::unique_ptr<Impl> m_Impl; // Pointe vers une classe opaque qui manipule mon HANDLE };
Puis j'ai réfléchi : un rapide coup d'oeil à la définition de HANDLE m'apprend qu'il s'agit d'un typedef vers void*. Pourquoi est-ce que je ne définirais pas alors ma classe comme ça :
Je ne pense pas casser quoi que ce soit de cette façon. Je n'empêche pas mon compilateur de faire de la vérification de type: lorsque, dans mon code non-portable, j'appelle une fonction comme WriteFile(), je peux lui passer un SystemHandle, puisqu'il s'agit du même type que celui auquel il s'attend. Et si ça venait à changer demain (si Microsoft définit HANDLE comme étant un int par exemple), j'aurais une erreur de compilation, mais facile à fixer.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class OutputDevice { typedef void* SystemHandle; public: // .... Diverses méthodes, constructeurs & destructeur // void Write (const std::string& out); private: SystemHandle m_Handle; // Type spécifique au système };
Je suis juste surpris de pas avoir vu ça plus souvent dans le source que je lis un peu partout, alors j'aimerais bien des avis extérieurs.
Merci !!!
Partager