Accueil > > > LE VECTEUR EST UN SACRÉ COPIEUR
LE VECTEUR EST UN SACRÉ COPIEUR
Information sur la source
Description
OK, le vecteur est beaucoup plus pratique que le tableau pour stocker les 'int' Mais que peut on lui confier à stocker ? avec quels avantages et inconvénients ? PARTIE I : le vecteur est vide, on lui ajoute un élément PARTIE II : le vecteur reçoit un deuxième élément PARTIE III : le vecteur reçoit un troisième élément PARTIE IV : l'insertion autre part qu'à la fin du tableau PARTIE V : Tentative d'optimisation de l'utilisation du vecteur PARTIE VI : Trop de copie ... on utilise des pointeurs... mais attention ! En conclusion : les bonnes pratiques et les interdits
Source
- //Le vecteur est un sacré copieur
- #include <iostream>
- #include <vector>
- using namespace std;
- /*On prendra une classe simple class A dotée d'un int pour "voir" comment les choses se passent */
- class A
- {
- private :
- int i_;
- public:
- A(int i=0) : i_(i){cout << "Ctor : " << i_ << endl;}
- // A(const A& a) : i_(a.i_){cout << "Ctor de copie : " << i_ << endl;} //a décommenter selon indication
- void print(ostream& out) const{ out << i_;}
- // ~A() {cout << "Dtor : " << i_ << endl;}
- };
- ostream& operator<<(ostream& out, const A& a) { a.print(out); return out;}
-
- int main()
- {
- //**********************************************************************
- //PARTIE I :le vecteur est vide, on lui ajoute un élément
- //**********************************************************************
- cout << "vector<A> v;" << endl;
- vector<A> v; //vecteur vide, destiné à stocker des objets A
-
- //ici, le vecteur est vide... la preuve :
- cout << "vecteur vide ? " << boolalpha << v.empty() << endl;
- A a1(1); //création d'un objet de type A
- cout << "v.push_back(a1);" << endl;
- v.push_back(a1);
- //ici, le vecteur n'est plus vide... la preuve :
- cout << "vecteur vide ? " << boolalpha << v.empty() << endl;
- //on peut accéder à sa capacité de stockage : combien d'éléments sont stockables sans nouvelle réallocation ?
- cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
- /*mais quel est l'objet qui a été stocké par le vector ?
- NON, la réponse a1 est FAUSSE ! Je vous avais prévenu (dans le titre de l'article)
- La bonne réponse est UNE COPIE DE a1 !
- Comment s'en apercevoir ? en traçant l'exécution du Ctor de copie => décommentez le
- On peut aussi chercher à écrire l'adresse mémoire du premier élément du vecteur : v[0]
- */
- cout << "@ de a1: &a1=" << &a1 << " et @ 1er element du vecteur &v[0]="<< &v[0] << endl;
- cout << "le vecteur lui-meme est en " << &v << " (pile)" << endl;
- /*on remarque ici que les adresses sont dans des plages différentes
- a1 est alloué sur la pile et l'objet copié dans le vecteur est alloué sur le tas...
- donc par de l'allocation dynamique...
- ce qui est nécessaire pour faire évoluer dynamiquement sa taille (augmentation ou diminution)
- */
- //**********************************************************************
- //PARTIE II : le vecteur reçoit un deuxième élément
- //**********************************************************************
- A a2(2); //création du deuxième objet de type A
- cout << "v.push_back(a2);" << endl;
- v.push_back(a2);
- /* Cette fois ci, la question est : qu'à fait le vecteur ?
- On sait qu'il a copié l'objet a2 est qu'il a ajouté la copie dans son conteneur
- mais allez voir la trace laissée par notre Ctor de copie !
- Pour mieux comprendre, allons voir l'adresse des deux éléments du vecteur
- */
- cout << " &v[0]="<< &v[0] << " et &v[1]="<< &v[1] << endl;
- cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
- //le conteneur (mémoire allouée) du vecteur se trouvait un peu à l'étroit à l'ancienne place,
- //il a donc déménagé dans un deux pièce... et copié chacun des éléments
- // Je vous avais prévenu ... blabla
-
- //**********************************************************************
- //PARTIE III : le vecteur reçoit un troisième élément
- //**********************************************************************
- A a3(3);
- cout << "v.push_back(a3);" << endl;
- v.push_back(a3);
- /* Cette fois ci, la question est qu'à fait le vecteur ?
- On sait maintenant qu'il a alloué suffisamment de place pour stocker les 3 éléments
- Mais il a anticipé les allocations futures et optimisé en allouant 4 objets... la preuve
- */
- cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << " et &v[2]="<< &v[2] << endl;
- cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
- /* Remarquons que ce comportement du vecteur n'est pas spécifié par les standards et que chaque
- implémentation peut se comporter différemment : le vecteur de l'implémentation VC++ alloue le double de la taille courante
- lors de chaque nouveau besoin
- Pour vérifier cela, que les éléments ne sont pas copiés cette fois ci, ajoutons un autre élément
- */
- cout << "v.push_back(a4);" << endl;
- v.push_back(A(4));
- cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << ", &v[2]="<< &v[2] << " et &v[3]="<< &v[3] << endl;
- cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
- //on retire alors cet élément
- cout << "pop_back de : " << v.back()<< " par v.pop_back();" << endl;
- v.pop_back();
- //remarque 1 : l'appel à pop_back() appelle le destructeur de l'objet chassé
- //remarque 2 : le pop_back ne renvoie rien, il convient d'avoir récupéré l'objet par back() si besoin est
- cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
- /*
- Pourquoi ces réallocations ?
- Car le vecteur est implémenté par un tableau en memoire dynamique ... et tous les éléments d'un tableau sont contigus
- C'est d'ailleurs ce qui rend le tableau si efficace lors de l'accès aléatoire par l'opérateur []
- L'élément 2 est alors récupéré directement par son adresse : adresse_début_tableau+2*sizeof(élément)
-
- **********************************************************************
- PARTIE IV : l'insertion autre part qu'à la fin du tableau
- **********************************************************************
- Il existe la possibilité d'insérer des éléments à la position de notre choix dans le tableau
- La méthode 'insert' permet cela, à condition de lui fournir un itérateur initialisé sur l'élément
- devant lequel on veut insérer notre nouvel élément.
- Par exemple, pour initialiser un itérateur au début du vecteur :
- */
- vector<A>::iterator it = v.begin();
- // Pour insérer un objet a4 :
- A a4(4);
- cout << "v.insert(v.begin(), a4);" << endl;
- v.insert(v.begin(), a4);//ou à des emplacements différents : v.insert(v.begin()+1, a4);
- //v.insert(it, a4);
- cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << ", &v[2]="<< &v[2] << ", &v[3]="<< &v[3] << " et &v[4]="<< &v[4] << endl;
- /* Que fait le vecteur à votre avis ?
- Comment ? il copie tout le monde ? tous les éléments suivant le point d'insertion ?
- et ceci, même s'il a suffisamment de place dans sa capacité ?
- PAS DU TOUT ! sur ce coup là, il optimise les appels au ctor de copie dans les déplacements mémoire
- C'est pour montrer ceci que nous avons retiré l'ancien 4ème élément dans la partie précédente.
- Mais au fait, comment les éléments sont ils déplacés ?
- Comme nos Ctors de copies ne sont pas appelés, la copie est faite par bit-copy
- */
- //ici des exemples de parcours du vecteur fonctionnellement identiques
- for (it=v.begin(); it!=v.end(); it++)//boucle avec itérateur
- cout << *it << " "; //impression de l?élément via l'itérateur (déréférencé)
- cout << endl;
- for (int i =0; i<v.size(); i++)//boucle simple
- cout << v[i] << " "; //impression de l?élément via l'opérateur []
- cout << endl;
- //ici une faible utilisation du vecteur, le parcours direct par un pointeur utilisateur
- A * ptr = &v[0];
- for (int ii=0; ii<4; ii++)
- cout << *ptr++ << " " ;
- cout << endl;
-
- /*********************************************************************
- PARTIE V : Tentative d'optimisation de l'utilisation du vecteur
- **********************************************************************
- Que de copies d'objet lorsque les insertions sont faites une par une !
- Dans le cas de figure ou nous savons à peu près combien d'objets seront mis dans le vecteur,
- l'idée est de TAILLER notre vecteur dès le début.
- Pour faire cela, tournons nous vers les Constructeurs du vecteur, nous en voyons un qui SEMBLE
- répondre à notre souhait
- explicit vector(size_type n, const T& v = T(), const A& al = A());
- Utilisons le pour vérifier son fonctionnement
- */
- cout << "vector<A> v2(5);" << endl;
- vector<A> v2(5);
- /*Qu'a t il fait ?
- BRAVO : il a copié ! il a d'abord utilisé le Ctor par défaut de A pour créer un objet temporaire
- il a ensuite utilisé cet objet temporaire comme source d'information pour la création par le Ctor de copie
- des autres éléments (les vrais) v2[0], .... v2[4] et il a ensuite détruit l'objet temporaire.
- On voit aussi que l'on peut choisir l'objet source de copie en codant ainsi :
- */
- cout << "vector<A> v3(5, A(10));\n";
- vector<A> v3(5, A(10));
- /*
- Quand un vecteur est trop petit, peux t on suggérer nous même l'aggrandissement ?
- OUI en utilisant la méthode resize()
- */
- cout << "avant resize : capacity=" << v3.capacity() << " et size=" << v3.size() << endl;
- cout << "v3.resize(20);\n";
- v3.resize(20);
- cout << "apres resize : capacity=" << v3.capacity() << " et size=" << v3.size() << endl;
- /*
- On a pas mal de copies, mais par rapport à la construction d'un vecteur vide suivi de push_back
- on gagne les réallocations mémoire et copies intermédiaires successives
- Mais n'y a t il pas un moyen de tailler le vecteur SANS CREER TOUS CES OBJETS ?
- La réponse est dans la méthode reserve()
- */
- vector<A> v4;
- cout << "\nv4.reserve(20); \n";
- v4.reserve(20);
- cout << "apres reserve : capacity=" << v4.capacity() << " et size=" << v4.size() << endl;
- //reserve est différent de resize dans la mesure ou il ne s'occupe que de la mémoire allouée
- //et PAS des objets du vecteur : pas de création et donc pas de copie
-
- /*************************************************************************
- PARTIE VI : Trop de copie ... on utilise des pointeurs... mais attention !
- **************************************************************************
- Que de copies d'objet ! l'idée suivante est de ne confier au conteneur que des pointeurs
- sur mes objets
- On va donc créer un objet dynamiquement et l'ajouter au vecteur
- */
-
- {
- A* pa=new A(1);
- vector<A*> v5;
- v5.push_back((A*)&v5);
- v5.resize(2);//cette fois ci, le resize ne fait pas de copie d'objet
- cout << "cap=" <<v5.capacity() << " et size=" << v5.size() << endl;
- //ici, une boucle jusqu'a size-1 provoquerait un TRAP
- for (int i =0; i<v5.size(); i++)//boucle simple
- // cout << *v5[i] << " "; //A décommenter pour voir le trap
- cout << endl;
- //ici, lorsque le vecteur va être détruit, ne pas oublier de libérer l'objet par
- delete pa; // car le destructeur de vector ne fera rien pour nos pointeurs
- }
- return 0;
- }
- /*
- En conclusion :
- La bonne pratique est d'anticiper la taille finale de l'objet vecteur dès sa construction
- ou au moins par une opération de reserve faite avant la première insertion.
- Ceci n'est pas toujours possible ... évidemment
-
- Les interdits :
- - si vous avez un objet lent à copier ou un objet non copiable (Ctor de copie privé)
- il est impossible d'utiliser le vecteur
- - De même, si votre objet ne possède pas de Ctor par défaut, l'utilisation du vecteur est handicappée
- car les resize y font appel
- - Pour éviter toutes les copies lourdes, on pourrait envisager de confier des pointeurs à notre vecteur
- Mais alors il faut gérer nous même la synchronisation du conteneur, des pointeurs et des objets
- En particulier, la création par new d'un objet et l'ajout du pointeur dans le vecteur nécessitera
- l'appel à delete lors de la destruction du vecteur... car le vecteur appellera seulement le destructeur
- de ce que nous lui avons confié... un pointeur. Le type pointeur n'étant pas une classe, aucun destructeur
- n'est appelé automatiquement.
- */
//Le vecteur est un sacré copieur
#include <iostream>
#include <vector>
using namespace std;
/*On prendra une classe simple class A dotée d'un int pour "voir" comment les choses se passent */
class A
{
private :
int i_;
public:
A(int i=0) : i_(i){cout << "Ctor : " << i_ << endl;}
// A(const A& a) : i_(a.i_){cout << "Ctor de copie : " << i_ << endl;} //a décommenter selon indication
void print(ostream& out) const{ out << i_;}
// ~A() {cout << "Dtor : " << i_ << endl;}
};
ostream& operator<<(ostream& out, const A& a) { a.print(out); return out;}
int main()
{
//**********************************************************************
//PARTIE I :le vecteur est vide, on lui ajoute un élément
//**********************************************************************
cout << "vector<A> v;" << endl;
vector<A> v; //vecteur vide, destiné à stocker des objets A
//ici, le vecteur est vide... la preuve :
cout << "vecteur vide ? " << boolalpha << v.empty() << endl;
A a1(1); //création d'un objet de type A
cout << "v.push_back(a1);" << endl;
v.push_back(a1);
//ici, le vecteur n'est plus vide... la preuve :
cout << "vecteur vide ? " << boolalpha << v.empty() << endl;
//on peut accéder à sa capacité de stockage : combien d'éléments sont stockables sans nouvelle réallocation ?
cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
/*mais quel est l'objet qui a été stocké par le vector ?
NON, la réponse a1 est FAUSSE ! Je vous avais prévenu (dans le titre de l'article)
La bonne réponse est UNE COPIE DE a1 !
Comment s'en apercevoir ? en traçant l'exécution du Ctor de copie => décommentez le
On peut aussi chercher à écrire l'adresse mémoire du premier élément du vecteur : v[0]
*/
cout << "@ de a1: &a1=" << &a1 << " et @ 1er element du vecteur &v[0]="<< &v[0] << endl;
cout << "le vecteur lui-meme est en " << &v << " (pile)" << endl;
/*on remarque ici que les adresses sont dans des plages différentes
a1 est alloué sur la pile et l'objet copié dans le vecteur est alloué sur le tas...
donc par de l'allocation dynamique...
ce qui est nécessaire pour faire évoluer dynamiquement sa taille (augmentation ou diminution)
*/
//**********************************************************************
//PARTIE II : le vecteur reçoit un deuxième élément
//**********************************************************************
A a2(2); //création du deuxième objet de type A
cout << "v.push_back(a2);" << endl;
v.push_back(a2);
/* Cette fois ci, la question est : qu'à fait le vecteur ?
On sait qu'il a copié l'objet a2 est qu'il a ajouté la copie dans son conteneur
mais allez voir la trace laissée par notre Ctor de copie !
Pour mieux comprendre, allons voir l'adresse des deux éléments du vecteur
*/
cout << " &v[0]="<< &v[0] << " et &v[1]="<< &v[1] << endl;
cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
//le conteneur (mémoire allouée) du vecteur se trouvait un peu à l'étroit à l'ancienne place,
//il a donc déménagé dans un deux pièce... et copié chacun des éléments
// Je vous avais prévenu ... blabla
//**********************************************************************
//PARTIE III : le vecteur reçoit un troisième élément
//**********************************************************************
A a3(3);
cout << "v.push_back(a3);" << endl;
v.push_back(a3);
/* Cette fois ci, la question est qu'à fait le vecteur ?
On sait maintenant qu'il a alloué suffisamment de place pour stocker les 3 éléments
Mais il a anticipé les allocations futures et optimisé en allouant 4 objets... la preuve
*/
cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << " et &v[2]="<< &v[2] << endl;
cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
/* Remarquons que ce comportement du vecteur n'est pas spécifié par les standards et que chaque
implémentation peut se comporter différemment : le vecteur de l'implémentation VC++ alloue le double de la taille courante
lors de chaque nouveau besoin
Pour vérifier cela, que les éléments ne sont pas copiés cette fois ci, ajoutons un autre élément
*/
cout << "v.push_back(a4);" << endl;
v.push_back(A(4));
cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << ", &v[2]="<< &v[2] << " et &v[3]="<< &v[3] << endl;
cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
//on retire alors cet élément
cout << "pop_back de : " << v.back()<< " par v.pop_back();" << endl;
v.pop_back();
//remarque 1 : l'appel à pop_back() appelle le destructeur de l'objet chassé
//remarque 2 : le pop_back ne renvoie rien, il convient d'avoir récupéré l'objet par back() si besoin est
cout << "capacite du vecteur = " << v.capacity() << ", taille = " << v.size() << endl;
/*
Pourquoi ces réallocations ?
Car le vecteur est implémenté par un tableau en memoire dynamique ... et tous les éléments d'un tableau sont contigus
C'est d'ailleurs ce qui rend le tableau si efficace lors de l'accès aléatoire par l'opérateur []
L'élément 2 est alors récupéré directement par son adresse : adresse_début_tableau+2*sizeof(élément)
**********************************************************************
PARTIE IV : l'insertion autre part qu'à la fin du tableau
**********************************************************************
Il existe la possibilité d'insérer des éléments à la position de notre choix dans le tableau
La méthode 'insert' permet cela, à condition de lui fournir un itérateur initialisé sur l'élément
devant lequel on veut insérer notre nouvel élément.
Par exemple, pour initialiser un itérateur au début du vecteur :
*/
vector<A>::iterator it = v.begin();
// Pour insérer un objet a4 :
A a4(4);
cout << "v.insert(v.begin(), a4);" << endl;
v.insert(v.begin(), a4);//ou à des emplacements différents : v.insert(v.begin()+1, a4);
//v.insert(it, a4);
cout << " &v[0]="<< &v[0] << ", &v[1]="<< &v[1] << ", &v[2]="<< &v[2] << ", &v[3]="<< &v[3] << " et &v[4]="<< &v[4] << endl;
/* Que fait le vecteur à votre avis ?
Comment ? il copie tout le monde ? tous les éléments suivant le point d'insertion ?
et ceci, même s'il a suffisamment de place dans sa capacité ?
PAS DU TOUT ! sur ce coup là, il optimise les appels au ctor de copie dans les déplacements mémoire
C'est pour montrer ceci que nous avons retiré l'ancien 4ème élément dans la partie précédente.
Mais au fait, comment les éléments sont ils déplacés ?
Comme nos Ctors de copies ne sont pas appelés, la copie est faite par bit-copy
*/
//ici des exemples de parcours du vecteur fonctionnellement identiques
for (it=v.begin(); it!=v.end(); it++)//boucle avec itérateur
cout << *it << " "; //impression de l?élément via l'itérateur (déréférencé)
cout << endl;
for (int i =0; i<v.size(); i++)//boucle simple
cout << v[i] << " "; //impression de l?élément via l'opérateur []
cout << endl;
//ici une faible utilisation du vecteur, le parcours direct par un pointeur utilisateur
A * ptr = &v[0];
for (int ii=0; ii<4; ii++)
cout << *ptr++ << " " ;
cout << endl;
/*********************************************************************
PARTIE V : Tentative d'optimisation de l'utilisation du vecteur
**********************************************************************
Que de copies d'objet lorsque les insertions sont faites une par une !
Dans le cas de figure ou nous savons à peu près combien d'objets seront mis dans le vecteur,
l'idée est de TAILLER notre vecteur dès le début.
Pour faire cela, tournons nous vers les Constructeurs du vecteur, nous en voyons un qui SEMBLE
répondre à notre souhait
explicit vector(size_type n, const T& v = T(), const A& al = A());
Utilisons le pour vérifier son fonctionnement
*/
cout << "vector<A> v2(5);" << endl;
vector<A> v2(5);
/*Qu'a t il fait ?
BRAVO : il a copié ! il a d'abord utilisé le Ctor par défaut de A pour créer un objet temporaire
il a ensuite utilisé cet objet temporaire comme source d'information pour la création par le Ctor de copie
des autres éléments (les vrais) v2[0], .... v2[4] et il a ensuite détruit l'objet temporaire.
On voit aussi que l'on peut choisir l'objet source de copie en codant ainsi :
*/
cout << "vector<A> v3(5, A(10));\n";
vector<A> v3(5, A(10));
/*
Quand un vecteur est trop petit, peux t on suggérer nous même l'aggrandissement ?
OUI en utilisant la méthode resize()
*/
cout << "avant resize : capacity=" << v3.capacity() << " et size=" << v3.size() << endl;
cout << "v3.resize(20);\n";
v3.resize(20);
cout << "apres resize : capacity=" << v3.capacity() << " et size=" << v3.size() << endl;
/*
On a pas mal de copies, mais par rapport à la construction d'un vecteur vide suivi de push_back
on gagne les réallocations mémoire et copies intermédiaires successives
Mais n'y a t il pas un moyen de tailler le vecteur SANS CREER TOUS CES OBJETS ?
La réponse est dans la méthode reserve()
*/
vector<A> v4;
cout << "\nv4.reserve(20); \n";
v4.reserve(20);
cout << "apres reserve : capacity=" << v4.capacity() << " et size=" << v4.size() << endl;
//reserve est différent de resize dans la mesure ou il ne s'occupe que de la mémoire allouée
//et PAS des objets du vecteur : pas de création et donc pas de copie
/*************************************************************************
PARTIE VI : Trop de copie ... on utilise des pointeurs... mais attention !
**************************************************************************
Que de copies d'objet ! l'idée suivante est de ne confier au conteneur que des pointeurs
sur mes objets
On va donc créer un objet dynamiquement et l'ajouter au vecteur
*/
{
A* pa=new A(1);
vector<A*> v5;
v5.push_back((A*)&v5);
v5.resize(2);//cette fois ci, le resize ne fait pas de copie d'objet
cout << "cap=" <<v5.capacity() << " et size=" << v5.size() << endl;
//ici, une boucle jusqu'a size-1 provoquerait un TRAP
for (int i =0; i<v5.size(); i++)//boucle simple
// cout << *v5[i] << " "; //A décommenter pour voir le trap
cout << endl;
//ici, lorsque le vecteur va être détruit, ne pas oublier de libérer l'objet par
delete pa; // car le destructeur de vector ne fera rien pour nos pointeurs
}
return 0;
}
/*
En conclusion :
La bonne pratique est d'anticiper la taille finale de l'objet vecteur dès sa construction
ou au moins par une opération de reserve faite avant la première insertion.
Ceci n'est pas toujours possible ... évidemment
Les interdits :
- si vous avez un objet lent à copier ou un objet non copiable (Ctor de copie privé)
il est impossible d'utiliser le vecteur
- De même, si votre objet ne possède pas de Ctor par défaut, l'utilisation du vecteur est handicappée
car les resize y font appel
- Pour éviter toutes les copies lourdes, on pourrait envisager de confier des pointeurs à notre vecteur
Mais alors il faut gérer nous même la synchronisation du conteneur, des pointeurs et des objets
En particulier, la création par new d'un objet et l'ajout du pointeur dans le vecteur nécessitera
l'appel à delete lors de la destruction du vecteur... car le vecteur appellera seulement le destructeur
de ce que nous lui avons confié... un pointeur. Le type pointeur n'étant pas une classe, aucun destructeur
n'est appelé automatiquement.
*/
Sources du même auteur
Sources de la même categorie
Commentaires et avis
|
Derniers Blogs
SESSION SILVERLIGHT 5 3D : SLIDES ET DEMOSSESSION SILVERLIGHT 5 3D : SLIDES ET DEMOS par Groc
Durant les techdays, j'ai eu le plaisir d'animer une session sur Silverlight 5 et la 3D avec Simon Ferquel. Comme promis, voici nos slides et mes démos (celles avec le viper BSG) ici et là. Pour mémoire, les démos utilisent toutes le viper BSG...
Cliquez pour lire la suite de l'article par Groc [TECHDAYS 2012] SESSION WEBMATRIX 2 : LE COUTEAU SUISSE GRATUIT POUR VOS DéVELOPPEMENTS WEB - SLIDES[TECHDAYS 2012] SESSION WEBMATRIX 2 : LE COUTEAU SUISSE GRATUIT POUR VOS DéVELOPPEMENTS WEB - SLIDES par gpommier
Suite à la session que j'ai présenté sur WebMatrix 2, vous pouvez trouver les slides ici, ainsi que les démos en packages nuget : démos1 et démos2 J'en profite pour remercier chaleureusement tous ceux qui sont venus très nombreux à cette sess...
Cliquez pour lire la suite de l'article par gpommier [SHAREPOINT] LES SESSIONS TECHDAYS 2012.[SHAREPOINT] LES SESSIONS TECHDAYS 2012. par Patrick Guimonet
Voici donc pour ceux qui n'ont pas pu venir, ou ceux qui n'ont pas pu toutes les suivre la liste des sessions SharePoint aux TechDays 2012, que je mettrais à jour dès que les liens des vidéo seront disponibles. Ou ici : http...
Cliquez pour lire la suite de l'article par Patrick Guimonet TECHDAYS PARIS 2012 : SESSION PLEINIèRE JOUR 3TECHDAYS PARIS 2012 : SESSION PLEINIèRE JOUR 3 par ROMELARD Fabrice
Speaker: Bernard Ourghanlian Cette session est comme chaque jour transmise en live par BrainSonic, et j'ai donc suivi cette troisième pleinière par ce moyen sur mon iPad . Elle est dédiée comme chaque année à la mise en perspective de l'é...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice MISHRA READER : UN LECTEUR RSS TRèS ZUNE STYLE EN OPEN SOURCE !MISHRA READER : UN LECTEUR RSS TRèS ZUNE STYLE EN OPEN SOURCE ! par Vko
Hier durant une session dédiée aux Techdays 2012, j'ai eu le plaisir d'annoncer la sortie de la Béta 2 de Mishra Reader. C'est quoi ? Pour les utilisateurs, c'est une vraie expérience de lecture de flux RSS sur Windows. Rien à voir avec les produit...
Cliquez pour lire la suite de l'article par Vko
Logiciels
Tribler (2012)TRIBLER (2012)Tribler est un client pair à pair (P2P/Peer-to-Peer) open source avec la capacité de regarder des... Cliquez pour télécharger Tribler OneSwarm (2012)ONESWARM (2012)Le peer-to-peer qui protège votre vie privée, c'est OneSwarm.
Ce logiciel de peer-to-peer crypté... Cliquez pour télécharger OneSwarm PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V8.4)PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V8.4)PONAMEDIA TV DEVIENS HELLLOOO FLASH
LA TV SUR VOTRE ORDINATEUR.
Toute une plateforme Multi... Cliquez pour télécharger PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO Academy System (17.2.1.0)ACADEMY SYSTEM (17.2.1.0)Logiciel de gestion des établissements.
- élèves/étudiants (inscription, dossier, absence...)
-... Cliquez pour télécharger Academy System Easy-Planning (1.0.0.1)EASY-PLANNING (1.0.0.1)Basé sur les mêmes principes que MyPlanning, Easy-Planning permet de créer des plannings sous la ... Cliquez pour télécharger Easy-Planning
|