Université de Sherbrooke, développement du jeu vidéo, CPA

Vous trouverez ici quelques documents et quelques liens pouvant, je l'espère, vous être utiles.

Les documents qui vous sont fournis ici le sont pour vous rendre service.

Je travaille très fort sur chacun de mes cours. Veuillez ne pas vendre (ou donner) les documents que je vous offre ici à qui que ce soit sans mon consentement. Si des abus surviennent, je vais cesser de rendre ce matériel disponible à toutes et à tous.

Si ces documents vous rendent service, faites-le moi savoir. Mon adresse de courriel est disponible à travers la page où on trouve mon horaire.

Vous trouverez sur ce site :

Documents sous forme électronique

Cliquez sur cette cible pour le plan de cours, sous forme électronique.

Contenu des séances

Ce qui suit détaille le contenu des séances du cours INF739.

Index des séances théoriques
S00 S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14
Date Séance Contenu

Vendredi 12 janvier AM

S00

Au menu :

Notez que nous examinons dans ce cours des techniques portables vers plusieurs plateformes et plusieurs compilateurs, mais que C++ 11 offre maintenant une API pleinement portable de threading et de synchronisation. Vous en verrez un exemple ici, et je vous montrerai comment en implémenter les bases vous-mêmes si vous le souhaitez.

Cela dit, il est possible (pour ne pas dire probable) que cette API ne soit pas disponible sur certaines des plateformes que vous rencontrerez dans l'industrie, du moins à court terme. Ainsi, ne vous en faites pas : en examinant des manières de procéder sans cette API, nous ne perdons pas notre temps.

Dans les notes de cours :

  • Pour l'essentiel, ce qui a été couvert aujourd'hui apparaît dans CPA – Volume 01, pp. ≈9-41

Vendredi 19 janvier AM

S01

Au menu :

Dans les notes de cours :

  • Les objets volatiles sont expliqués dans CPA – Volume 01, pp. ≈99-123
  • Un tableau résumant les impacts du mot volatile apparaît dans CPA – Volume 01, p. 117
  • À propos de l'atomicité, voir Atomicite.pdf (document qui demande à être retravaillé, mais c'est mieux que rien)

J'ai montré un petit exemple d'implémentation réduite de std::async() à titre illustratif, acceptant une fonction int(*)(int) et un paramètre int puis retournant une future<int>. Voici une version un peu plus complète (je n'ai pas tenu compte des politiques de démarrage comme std::launch_async et std::launch_defer) :

template <class T, class F, class ... Args>
   auto async(F f, Args && ... args) -> decltype(f(std::forward<Args>(args)...)) {
      promise<T> ze_promesse;
      future<T> ze_future = ze_promesse.get_future();
      thread th{ [](promise<T>&& p, F f, Args && ... args) {
         try {
            p.set_value(f(std::forward<Args>(args)...));
         }
         catch (...) {
            p.set_exception(current_exception());
         }
      }, std::move(ze_promesse), f, std::forward<Args>(args)... };
      th.detach();
      return ze_future;
   }

Ceci ne signifie pas que votre implémentation soit écrite exactement comme ceci, mais c'est l'idée.

J'ai aussi fait une petite activité pour compter les vilains dans une carte de grande taille, en séquentiel puis en parallèle. Tel que mentionné en classe, ne faites pas circuler cet exemple (c'est un exercice que j'utilise à l'occasion quand je donne des formations en entreprise). Le code suit :

#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
#include <chrono>
#include <locale>
#include <future>
#include <random>
#include <algorithm>
#include <numeric>
using namespace std;
using namespace std::chrono;

template <class F, class ... Args>
auto tester(F f, Args &&... args) {
   auto pre = high_resolution_clock::now();
   auto res = f(std::forward<Args>(args)...);
   auto post = high_resolution_clock::now();
   return make_pair(res, post - pre);
}

enum class Case : unsigned char {
   Vide, Heros, Mur, Vilain, Bibitte
};

int main() {
   locale::global(locale{ "" });
   enum { LARGEUR = 25'000, HAUTEUR = 25'000 };
   vector<Case> carte(LARGEUR * HAUTEUR, Case::Vide);
   random_device rd;
   mt19937 prng{ rd() };
   uniform_int_distribution<int> d100{ 1,100 }, d4{ 1,4 };
   auto temps_init = tester([&] {
      generate(begin(carte), end(carte), [&] {
         return d100(prng) <= 85 ? Case::Vide :
            static_cast<Case>(d4(prng));
      });
      return 0;
   });
   cout << "Initialisation complétée en "
        << duration_cast<milliseconds>(temps_init.second).count()
        << " ms." << endl;
   cout << "Nb pas gentils (séquentiel) : ";
   auto seq = tester([&] {
      return count_if(begin(carte), end(carte), [](Case c) {
         return c == Case::Bibitte || c == Case::Vilain;
      });
   });
   cout << seq.first << " obtenu en "
        << duration_cast<milliseconds>(seq.second).count()
        << " ms." << endl;
   //
   // Ok, on y va...
   //
   cout << "Nb pas gentils (parallèle) : ";
   auto para = tester([&] {
      auto ncoeurs = thread::hardware_concurrency();
      const auto taille_bloc = carte.size() / ncoeurs;
      vector<future<int>> v;
      for (decltype(ncoeurs) i = 0; i != ncoeurs - 1; ++i)
         v.emplace_back(async([deb = begin(carte) + i * taille_bloc,
            fin = begin(carte) + (i + 1) * taille_bloc]{
            return count_if(deb, fin, [](Case c) {
               return c == Case::Bibitte || c == Case::Vilain;
            });
         }));
      auto n = count_if(begin(carte) + (ncoeurs - 1) * taille_bloc,
         end(carte), [](Case c) {
         return c == Case::Bibitte || c == Case::Vilain;
      });
      return accumulate(begin(v), end(v), n, [](int so_far, future<int> &f) {
         return so_far + f.get();
      });
   });
   cout << para.first << " obtenu en "
        << duration_cast<milliseconds>(para.second).count()
        << " ms." << endl;
}

Enfin, j'ai fait une démonstration des coûts du faux-partage (attention : compilez en 64 bits dû à la taille du vecteur). Le code suit :

#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
#include <chrono>
#include <locale>
#include <future>
#include <random>
#include <algorithm>
#include <numeric>
using namespace std;
using namespace std::chrono;

template <class F, class ... Args>
auto tester(F f, Args &&... args) {
   auto pre = high_resolution_clock::now();
   auto res = f(std::forward<Args>(args)...);
   auto post = high_resolution_clock::now();
   return make_pair(res, post - pre);
}

int main() {
   locale::global(locale{ "" });
   enum { N = 25'000 };
   vector<int> mat(N * N);
   auto taille_bloc = mat.size() / 8; // hardware_concurrency
   iota(begin(mat), end(mat), 1); // approx. la moitié est impaire
   auto r0 = tester([&] {
      int nimpairs[8]{}; // initialisés à zéro; 8 == hardware_concurrency
      vector<thread> th;
      for (int i = 0; i != 8; ++i)
         th.emplace_back([&, i, taille_bloc] {
         for (int j = i * taille_bloc; j != (i + 1) * taille_bloc; ++j)
            if (mat[j] % 2 != 0)
               nimpairs[i]++;
      });
      for (auto & thr : th) thr.join();
      return accumulate(begin(nimpairs), end(nimpairs), 0);
   });
   cout << "Par. Nb impairs au total : " << r0.first
        << " obtenu en " << duration_cast<milliseconds>(r0.second).count()
        << " ms." << endl;
   auto r1 = tester([&] {
      int nimpairs = 0;
      for (size_t j = 0; j != mat.size(); ++j)
         if (mat[j] % 2 != 0)
            nimpairs++;
      return nimpairs;
   });
   cout << "Seq. Nb impairs au total : " << r1.first
        << " obtenu en " << duration_cast<milliseconds>(r1.second).count()
        << " ms." << endl;
   auto r2 = tester([&] {
      int nimpairs[8]{}; // initialisés à zéro; 8 == hardware_concurrency
      vector<thread> th;
      for (int i = 0; i != 8; ++i)
         th.emplace_back([&, i, taille_bloc] {
            int n = 0;
            for (int j = i * taille_bloc; j != (i + 1) * taille_bloc; ++j)
               if (mat[j] % 2 != 0)
                  n++;
            nimpairs[i] = n;
         });
      for (auto & thr : th) thr.join();
      return accumulate(begin(nimpairs), end(nimpairs), 0);
   });
   cout << "Par. Nb impairs au total : " << r2.first
        << " obtenu en " << duration_cast<milliseconds>(r2.second).count()
        << " ms." << endl;
}

Mardi 23 janvier PM

S02

Au menu :

  • Q00
  • Les sockets de type flux :
    • exploration brève du modèle de programmation
    • examen rapide des distinctions entre le modèle BSD de base, qui est universel, et certaines implémentations OO construites par-dessus
    • réflexion sur les limites de ce qui peut être transigé entre deux homologues situés dans des espaces adressables distincts
    • réflexion aussi sur les distinctions structurelles entre les architectures matérielles, en particulier en ce qui a trait à la structure interne des entiers

Dans les notes de cours :

  • Les sockets de type flux sont décrits dans CPA – Volume 02, pp. ≈6-36

Vendredi 26 janvier AM

S03

Au menu, activité pratique :

  • En équipe de deux personnes, implémentez un système client/ serveur où le serveur peut gérer plusieurs clients de manière concurrente
  • Le client devra envoyer au serveur un nom de fichier (vous devez supporter à la fois les fichiers « texte » et « binaires »). Le nom peut inclure un chemin (p. ex. : "c:\machin\truc\yo man.jpeg" ou "../projet.sln"), et les répertoires relatifs seront considérés sur la base du répertoire de travail du serveur
  • Le serveur devra consommer ce nom, puis transférer le contenu du fichier en question au client
  • Le client devra consommer le contenu du fichier, et écrire ce fichier dans son propre répertoire de travail (excluant le chemin s'il y a lieu)
  • On doit pouvoir vérifier que le fichier reçu et écrit sur le poste du client est identique au fichier d'origine (ça peut être aussi simple que de l'ouvrir  )
  • Présentez à votre chic prof le code source du client et du serveur pour rétroaction sur le code (on peut faire cela en classe si vous le souhaitez)

Je serai avec vous, en soutien. L'idée ici est de s'assurer que vous êtes en mesure de bien gérer plusieurs séances concurrentes de transfert de fichiers, que vous gérez adéquatement les ressources associées à ces transactions, et que vous êtes familiarisés avec les sockets de type flux.

J'ai préparé quelques exemples de type « solutionnaire » pour vous aider :

En espérant que le tout vous soit utile!

Mardi 30 janvier PM

S04

Au menu :

  • Q01
  • Les sockets de type datagramme :
    • comparaison avec les sockets de type flux
    • différences protocolaires
    • combiner struct et union (les union étiquetés)
    • portabilité des données
  • Considérations de sérialisation (texte)

Voici un exemple simple de sérialisation brute adaptative :

#define NOMINMAX // car windows.h, inclus « par la bande », et un vilain garnement
#include <winsock2.h>
#pragma comment(lib,"Ws2_32.lib")

#include <iostream>
#include <algorithm>
#include <cassert>
#include <string>
#include <type_traits>
#include <iterator>
using namespace std;

template <class T>
T normaliser(T val) { return val; }

short normaliser(short val) { return htons(val); }
int normaliser(int val) { return htonl(val); }
long normaliser(long val) { return htonl(val); }

template <class T>
   enable_if_t<is_integral<T>::value, char *>
      serialiser_brut(const T &val, char *p) {
      static_assert(is_trivially_copyable_v<T>);
      auto valeur = normaliser(val);
      copy(reinterpret_cast<const char *>(&valeur),
           reinterpret_cast<const char *>(&valeur + 1), p);
      return p + sizeof(T);
   }
template <class T>
   enable_if_t<!is_integral<T>::value, char *>
      serialiser_brut(const T &val, char *p) {
      static_assert(is_trivially_copyable_v<T>);
      copy(reinterpret_cast<const char *>(&val),
           reinterpret_cast<const char *>(&val + 1), p);
      return p + sizeof(T);
   }
int main() {
   float f = 3.14159f;
   long lg = 3L;
   char c = 'A';
   string s = "J'aime mon prof";
   char buf[sizeof(f) + sizeof(lg) + sizeof(c)] = {};
   auto p = begin(buf);
   p = serialiser_brut(f, p);
   p = serialiser_brut(lg, p);
   p = serialiser_brut(c, p);
   // p = serialiser_brut(s, p); // illégal!
   assert(p == end(buf));
}

Dans les notes de cours :

  • Les sockets de type datagramme sont décrits dans CPA – Volume 02, pp. ≈61-70
  • La sérialisation est discutée en détail dans CPA – Volume 03, pp. ≈10-46

Vendredi 2 février AM

S05

Au menu :

Mardi 6 février PM

S06

Au menu :

  • Q04
  • Construction d'un pointeur intelligent implémentant une sémantique de partage – sorte de shared_ptr maison – pour voir et comprendre ce que cela implique
    • ça semble court comme menu, mais c'est vraiment rien de simple

La semaine du 12 au 16 février, notre cours fait relâche. Bon travail sur votre projet, les amis!

Mardi 20 février PM

S07

Au menu :

Vendredi 23 février AM

S08

Au menu :

J'ai écrit un délégué « live » avec vous en classe, avec une sémantique différente de celle mise de l'avant par std::function. Le code suit, au cas où ce serait utile :

template <class R, class A>
   class delegue {
      struct Appelable {
         virtual R appeler(A) const = 0;
         virtual ~Appelable() = default;
         virtual Appelable *cloner() const = 0;
      };
      Appelable *p;
      struct PtrFonction : Appelable {
         R(*pf)(A);
         PtrFonction(R(*pf)(A)) noexcept : pf{ pf } {
         }
         R appeler(A arg)  const override{
            return pf(arg);
         }
         PtrFonction *cloner() const override {
            return new PtrFonction{ *this };
         }
      };
      template <class T>
         struct PtrMethode : Appelable {
            R(T::*pm)(A) const;
            T obj;
            PtrMethode(T obj, R(T::*pm)(A) const) : obj{ obj }, pm{ pm } {
            }
            R appeler(A arg) const override {
               return (obj.*pm)(arg);
            }
            PtrMethode *cloner() const override {
               return new PtrMethode{ *this };
            }
         };
      template <class F>
         struct Foncteur : Appelable {
            F obj;
            Foncteur(F obj) : obj{ obj } {
            }
            R appeler(A arg) const override {
               return obj(arg);
            }
            Foncteur *cloner() const override {
               return new Foncteur{ *this };
            }
         };
   public:
      delegue() noexcept : p{} {
      }
      bool empty() const noexcept {
         return !p;
      }
      delegue(R(*pf)(A)) : p{ new PtrFonction{ pf } } {
      }
      template <class T>
         delegue(T obj, R(T::*pm)(A) const) : p{ new PtrMethode<T>{ obj, pm } } {
         }
      template <class F>
         delegue(F f) : p{ new Foncteur<F>{ f } } {
         }
      ~delegue() {
         delete p;
      }
      delegue(const delegue &autre) : p{ autre.p ? autre.p->cloner() : nullptr } {
      }
      void swap(delegue &autre) {
         using std::swap;
         swap(p, autre.p);
      }
      delegue& operator=(const delegue &autre) {
         delegue{ autre }.swap(*this);
         return *this;
      }
      R operator()(A arg) const {
         return p->appeler(arg);
      }
   };

int f(double x) {
   return static_cast<int>(x);
}
struct F {
   int operator()(double x) const {
      return static_cast<int>(x * 2);
   }
};
struct Obj {
   int meth(double x) const {
      return static_cast<int>(-x);
   }
};

#include <iostream>
using namespace std;
int main() {
   delegue<int, double> del = f;
   cout << del(3.5) << endl; // 3
   del = F{};
   cout << del(3.5) << endl; // 7
   Obj obj;
   del = delegue<int, double>{ obj, &Obj::meth };
   cout << del(3.5) << endl; // -3
}

Remise de L00

Mardi 27 février PM

S09

Au menu :

  • Q06
  • Comprendre le type std::tuple
  • Facettes
  • Petit défi technique : implantons un mécanisme de facettes non-intrusive (au sens où il n'oblige pas les facettes à dériver elles-mêmes de Facette) tel que le programme ci-dessous fonctionne, n'entraîne pas de fuites de ressources, et offre l'affichage attendu. Le code client imposé est :
#include "FacetteServer.h"
#include <iostream>
struct Texture {
   const char *getTextureName() const noexcept {
      return "Je suis un nom de texture";
   }
};
struct TextureManager {
   Texture getTexture() const noexcept {
      return {};
   }
};
struct Sound {
   const char *getFileName() const noexcept {
      return "SomeSound.wav";
   }
};
struct SoundManager {
   Sound getSound() const noexcept {
      return {};
   }
};
int main() {
   using namespace std;
   auto &serveur = FacetteServer::get();
   serveur.installer(TextureManager{});
   serveur.installer(SoundManager{});
   // ...
   cout << utiliser_facette<SoundManager>(serveur).getSound().getFileName() << endl;
   cout << utiliser_facette<TextureManager>(serveur).getTexture().getTextureName() << endl;
}

La sortie attendue est :

SomeSound.wav
Je suis un nom de texture

Mardi 6 mars PM

S10

Au menu :

Vendredi 9 mars AM

S11

Au menu :

  • Une présentation du très chic Patrick Hubert, d'Autodesk, qui dissertera entre autres sur son vécu comme développeur dans le monde du jeu vidéo et de l'intégration de code Python et de code C++
  • Une présentation du très chic David Viens, de Plogue.com, qui discutera de son expérience particulière de dirigeant de petite entreprise techno dans le monde de la musique et de systèmes temps réel

La semaine du 12 mars au 16 mars, notre cours fait relâche. Je serai à la rencontre du WG21 à Jacksonville; voir ../../Sujets/Orthogonal/wg21-2018-Jacksonville.html si vous voulez suivre mes aventures.

Les semaines du 19 mars, 26 mars et 2 avril, notre cours fait relâche. Bon travail sur votre projet, les amis. Prenez soin de ne pas oublier tout ce que nous avons fait jusqu'ici!

Mardi 10 avril PM

s/o

Séance déplacée au 12 avril à 18 h 30 pour profiter d'un conférencier spécial

Jeudi 12 avril PM (18 h 30)

S12

Au menu :

  • Séance spéciale de soirée, avec la présence virtuelle de Chris Spears. Dans ses propres mots, sa notice biographique est :
    • « I started programming on a TRS-80 with 4k of ram in the late 70's. I started teaching programming in high school in the 80's because there were no teachers who knew how to program at the school. In the late 80's I was teaching a crazy new language called "C++" at a university and coding for MUDs. Around 1991 I started coding professionally for computer games and have been doing so ever since pretty much always as a lead programmer, tech director, or CTO »
  • Les sujets prévus au menu sont, toujours dans ses mots :
    • Tech stuff (PC, Consoles, MMO's, mobile, smart toys, Web games, and lots of cross platform stuff)
    • Crowdfunding projects
    • Crowdsourcing on projects
    • Completely open development (we keep no secrets from the player and even post our daily standup notes)
    • What it is like working with industry legends (Richard and Starr but previously I was director on a few Star Wars games including Lucas' pet project, Darth Maul)
    • A topic I think might be sexy to college kids is data mining and how we use it in games
    • Discuss the evolution of our project planning from waterfall and gant charts to Scrum to where we are today with just flexible agile
    • Talk about pros and cons of working in the games industry since I have experience working as first party, contractor to a big publisher, as a VC funded startup, to a completely crowdfunded indie
    • AND if desired, I can also talk about tech and how I've seen development evolve over time in addition to various future tech stuff
  • Vos questions seront les bienvenues, alors n'hésitez pas à vous préparer en conséquence!

Mardi 17 avril PM

S13

Au menu :

  • Une présentation d'André Caron, programmeur chez Ubisoft, portant sur les jeux en ligne et sur les problèmes de grande envergure :
    • ce dont il s'agit
    • leur place dans l'industrie
    • enjeux et les particularités techniques intéressantes, etc.

Changement de plan : André Caron est coincé au bureau pour une urgence cette semaine et a dû se décommander.

  • Q08
  • Q09
  • Rapport de voyage, en particulier les enjeux qui touchent directement notre cours :
    • Annotation [[no_unique_address]], utile en particulier dans le cas des classes terminales
    • Annotations [[likely]] et [[unlikely]]
    • Contrats
    • Destroying operator delete
    • <span>
    • Itérateurs constexpr
    • simd<T> pour le Parallelism TS v2
    • Static Reflection TS
    • Coroutines et transfert de contrôle symétrique
  • Aussi intéressants, mais d'un autre ordre :
    • SG15
    • SG16
    • Dates et fuseaux horaires
    • Down with typename!
    • Destructeurs constexpr
    • Travaux sur la syntaxe concise des concepts
    • λ et capture variadique
    • Affectation déstructurante (Structured Bindings) et accessibilité
    • J'ai appris que les qualifications d'accès voyagent dans le temps :
struct A {
protected:
  struct B {
  };
};
struct X : A::B, A {
};
int main() {
  X x;
}
    • Cas analogues au problème de l'arrêt
#include <cstdio>
#include <cstdlib>
void f() {
  struct X {
    ~X() {
      std::puts("unwound");
      std::exit(0);
    }
  } x;
  throw 0;
}
int main(int argc, char**) {
  try {
    f();
  } catch (int) {
    std::puts("caught");
  }
}
    • Quelques horreurs (toujours amusantes), par exemple :
struct A {
   int n = A{}.n;
}; 
    • ... ou encore :
struct A { int x, y; };
A passthrough(A a) { return a; }
int main(void) {
   A a;
   a.x = 0;
   return passthrough(a).x; // Oups! UB!
}

Pour le reste, on y va selon vos questions et besoins.

La semaine du 23 avril, notre cours fait relâche. Bon travail sur votre projet, les amis!

Mardi 1er mai PM

S14

Remise de L01, puis un chic examen final vous attend!

Résultats des questions quasi-hebdomadaires

Les moyennes des résultats obtenus aux questions quasi-hebdomadaires pour la session en cours suivent. Notez que l'écart-type n'est pas significatif étant donné la pondération des questions (sur cinq points, un point de différence représente , ce qui bousille quelque peu cette composante statistique).

 Question   Séance 
Q00 S02
Q01 S04
Q02 S05
Q03 S05
Q04 S06
Q05 S08
Q06 S09
Q07 S10
Q08 S13
Q09 S13
 :
(huit meilleurs) :

Consignes des livrables

Les consignes des livrables L00 et L01 suivent (dates de remise incluses).

Livrable 00

Voici les consignes du livrable L00 :

Vous constaterez que je ne vous impose pas de livraison de code. Un document bref (disons 6-8 pages) par équipe suffira. J'aimerais l'avoir le 22 février du fait que c'est probablement déjà pensé et fait et que ça peut demeurer succinct.

Livrable 01

Voici les consignes du livrable L01. Les éléments demandés sont des éléments d'équipe, sauf pour une exception indiquée clairement plus bas :

Un document bref suffira pour chaque équipe, disons 6-8 pages pour le volet équipe et quelques pages par personne pour le volet personnel. Pour la date et pour le mode de livraison, je vous suggère ceci :

Ça vous va? Sinon, faites-moi signe...

Attentes dans le projet de session en lien avec ce cours

Le cours INF739 couvre plusieurs sujets quelque peu disparates. Sachant cela, pour rencontrer les attentes de ce cours, votre projet de session devra lui aussi rencontrer quelques attentes éparses :

Les consignes des livrables vont plus en détail; n'hésitez pas à communiquer avec moi si vous souhaitez des clarifications.

Exemples de code

Ce qui suit vous est gracieusement offert dans le but de vous épargner une recopie pénible d'exemples et de tests proposés dans les notes de cours.

Sources des exemples du document CPA – Volume 00

Cliquez sur cette cible pour obtenir le code de la chaîne pascal simplifiée

Cliquez sur cette cible pour obtenir le code de la chaîne pascal avec itérateurs

Cliquez sur cette cible pour obtenir le code du test 0.0

Cliquez sur cette cible pour obtenir le code du test 0.0b

Cliquez sur cette cible pour obtenir le code du test 0.1

Cliquez sur cette cible pour obtenir le code du test 1.0

Cliquez sur cette cible pour obtenir le code du test 1.1

Cliquez sur cette cible pour obtenir le code du test 1.2

Cliquez sur cette cible pour obtenir le code du test 1.3

Cliquez sur cette cible pour obtenir le code du test 2.0

Cliquez sur cette cible pour obtenir le code du test 2.1

Cliquez sur cette cible pour obtenir le code du test 2.2

Cliquez sur cette cible pour obtenir le code du test 3.0

Sources (pas à jour; prudence!) des exemples du document CPA – Volume 01

Cliquez sur cette cible pour obtenir le code du cas 0

Cliquez sur cette cible pour obtenir le code du cas 1

Cliquez sur cette cible pour obtenir le code du cas 2

Cliquez sur cette cible pour obtenir le code du cas 3

Cliquez sur cette cible pour obtenir le code du cas 4

Sources de projets utilisant des sockets

Cliquez ici pour le projet contenant le code du client multiprogrammé de conversation, format « vanille ».

Cliquez ici pour le projet contenant le code du serveur multiprogrammé conversation « vanille ».

Cliquez ici pour le projet contenant le code du client multiprogrammé de conversation, format « objets autonomes ».

Cliquez ici pour le projet contenant le code du serveur multiprogrammé conversation « objets autonomes ».

Sources de divers exemples qui doivent être retouchés à la lueur de C++ 11

Cliquez sur cette cible pour obtenir le code source de la classe pattern_iterator, document CPA – Volume 02 (ou encore cet article).

Cliquez sur cette cible pour obtenir le code à optimiser pour EX00, série 04, document CPA – Volume 03.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 00, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 01, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 02, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 03, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 04, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 05, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 06, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet du sélecteur de conversions, tel qu'il apparaît dans le document CPA – Volume 04.

Documents sous forme électronique

Cliquez sur cette cible pour aller au document portant sur les classes imbriquées.

Cliquez sur cette cible pour aller au document portant sur les templates.

Cliquez sur cette cible pour aller au document portant sur les singletons.

Cliquez sur cette cible pour aller au document portant sur les mutex portables .

Cliquez sur cette cible pour aller au document portant sur les autoverrous.

Cliquez sur cette cible pour aller au document portant sur les objets autonomes.

Cliquez sur cette cible pour aller au document portant sur les méthodes volatiles.

Cliquez sur cette cible pour aller au document portant sur la conversion automatique entre référentiels.

De manière plus générale, je vous suggère les sections Développement, Questions diverses de C++ et Trucs scouts de h-deb


Valid XHTML 1.0 Transitional

CSS Valide !