Astuces pour bien coder en C++

C++-unofficial.sh-600x600

Intro :

Voici quelques astuces qui vous permettrons de mieux vous organiser dans l’étape d’écriture de votre code.

Safe Delete :

Pour détruire correctement vos objets instanciés, vous pouvez utiliser ces macros :


#define SAFE_DELETE(a) { delete (a); (a) = nullptr; }
#define SAFE_RELEASE(x) { x->Release();  (x) = nullptr; }

SAFE_DELETE(a);
SAFFE_RELEASE(x);


Fichier de déclaration de defines :

Utiliser un fichier include (Defines.h) où vous mettrez toutes vos déclarations de defines.
Par principe il vaut mieux  regrouper ensemble tout ce qui se ressemble.


#define FIRST_PERSON_CAMERA_SPEED 3.0f
#define OGRE_RENDER_SYSTEM_NAME "Direct3D9 Rendering Subsystem"
#define TIME_FADE_ANNOUNCE 2.0f
#define GAME_VERSION_REVISION "2323"
#define GAME_VERSION_MINOR "1"
#define GAME_VERSION_MAJOR "0"


Commentaires :

En général il vaut mieux bien nommer correctement les noms des variables et des fonctions
plutôt que de mettre des commentaires partout.

« Really good code comments itself » :

Sortie de texte pour débugger :

Sous Visual Studio on peut utiliser :

OutputDebugString(_T("text"));

Cela permettra au programme d’écriture sur la sortie debug de VC++.


En-tête :

Pour expliquer et situer le rôle d’un fichier source vous pouvez créer une en-tête dans chaque fichier :


//----------------------------------------------------
// Auteur : Clément Profit
// Nom du fichier : Console.cpp
// Date de création : Juillet 2014
// Description : Une console quake-like avec commandes et
// appels d'events
//----------------------------------------------------

Pour expliquer et situer le rôle d’une méthode :


//--------------------------------------------------
// EventManager::Trigger
//--------------------------------------------------

 

Principes :

1 – ne jamais arrêter son travail quand le programme ne fonctionne pas ou lorsqu’il ne compile pas. En effet lors de la reprise ultérieure de votre travail vous aurez pas de bug(s) à corriger que vous aurez oubliés de résoudre.

2 – pensez à abuser l’utilisation des macros lorsque votre code devient répétitif.

Macro prédéfinies :

Nom de la fonction courante :


#if defined(_MSC_VER)
    #define CURRENT_FUNCTION_NAME __FUNCTION__
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
    #define CURRENT_FUNCTION_NAME __PRETTY_FUNCTION__
#else
    #define CURRENT_FUNCTION_NAME "Unknown function"
#endif

Pour le reste voir l’article Préprocesseur

Assertions :

Utiliser ces assertions un peu partout dans votre code.
L’instruction asm { int 3 } indiquera au débogueur un point d’arrêt près de l’assertion en cause.


#ifndef ASSERT_H
#define ASSERT_H

#ifndef NDEBUG

#define AssertMsg(expr, msg) if (!(expr)) { std::wout << (#expr << " " << __FILE__ << " " << __LINE__ << " " << CURRENT_FUNCTION_NAME << " " << msg << std::endl); __asm { int 3 } }
#define AssertNULLPointer(pointer) if (pointer == NULL) { AssertMsg(pointer, #pointer " == NULL"); __asm { int 3 } }
                    
#else //! non-debug

#define AssertMsg(expr, msg) fastprint(msg);
#define SKIP_IF_FAILED_AssertMsg(expr, msg) if (expr)
             
#endif
                                             
#endif

Notations :

Utiliser la notation hongroise pour noter vos variables et vos noms de fonctions :

g : utiliser pour les variables globales – g_counter
m : utiliser pour les variables membres – m_counter
p : utiliser pour les variables pointeurs – m_pActor
V : utiliser pour les fonctions virtuelles – VDraw()
I : utiliser pour les classes interfaces – class IDrawable

Exemple :


Ogre::OverlayManager* m_pOverlayManager;
Ogre::Overlay* m_pOverlayConsole;
Ogre::OverlayContainer* m_pPromptImage;

std::string m_sCurrentCommmandLine;
std::string m_sPrompt;

float m_fScrollYOffset;
float m_fHeight;
float m_fWidth;
float m_fCharWidth;

Les différents types de style de codage peuvent être source de conflit entre programmeurs.

L’important est d’être régulier dans la beauté de la syntaxe,
peu importe quel style / norme de codage vous employez.

Utiliser des raccourcis pour vos classes singletons :


#define EVENT_MANAGER EventManager::getSingletonPtr()


Macro fastprint(texte) :

Pour imprimer du texte ou une variable rapidement (la macro supporte du texte « wide string » c’est-à-dire supportant l’alphabet français contrairement à printf ou à std::cout).


#define fastprint(msg) std::wcout << #msg " = " << msg << std::endl;

 

Macro debugprint(texte) :

Pour déboguer vos applications on se sert de cette macro pour afficher facilement une variable

#define debugprint(msg) std::cout << msg << " = " << std::endl;

(todo mulitples paramètres)

 

Constructeur :

Ne jamais faire échouer l’initialisation d’un objet dans son constructeur.
Définissez une méthode bool Initialize() à la place (qui peut échouée quant-à-elle) que vous appelez juste après le « new » et qui renvoit un booléen indiquant si ou non l’initialisation de l’objet à échouée.

DXTrace :

Pour afficher éventuellement une erreur DirectX, on peut utiliser cette macro :

#if defined(DEBUG) | defined(_DEBUG)
    #ifndef HR
    #define HR(x)                                      \
    {                                                  \
        HRESULT hr = x;                                \
        if(FAILED(hr))                                 \
        {                                              \
            DXTrace(__FILE__, __LINE__, hr, #x, TRUE); \
        }                                              \
    }
    #endif

#else
    #ifndef HR
    #define HR(x) x;
    #endif
#endif

 

Const correctness  :

 

Faire une pause dans le programme :


#define WAIT_PROCESS int i; std::cin >> i; // Ne pas utiliser system("pause"); !

 

Utilisation de la fenêtre Outline de Visual Studio C++ :

Il est aisé de naviguer à travers les méthode de vos classe avec cette fenêtre.

outlines

 

Bien choisir la taille de ses types :

Utilisez uint16 à la place de uint32 quand cela est possible, cela réduira la taille consommée par votre programme à l’exécution. Vous pouvez continuer à utiliser uint32 lorsque que la variable est utilisée temporairement (par exemple dans les boucles), en effet il n’est pas important d’utiliser des variables de type uint16 sur la pile car elles sont détruites tout de suite après la portée, il faut utiliser des uint16 uniquement sur le tas.


// Après avoir ignorer un bloc de code on nous propose la reprise du programme en cours
#define SKIP_IF_FAILED_AssertMsg(expr, msg) if (!(expr)) \
FailedAssertMessageBox(#expr, __FILE__, __LINE__, CURRENT_FUNCTION_NAME, msg, true); \
else

Résumé :

Ces méthodes permettent de faciliter le codage de vos programme et de
rendre le code plus clair et plus joli.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *