bah pense que tes threads partagent les ressources physiques de ta machine. Donc si ils ne sont pas vraiment actif en meme temps, tu peux avoir 1000/10000/100000 threads sans soucis. Si ils sont tous actifs en meme temps, vise en gros un thread par contexte materiel.
Nan les thread s'occuperont juste de créer une requête, ce qui prends relativement peu de temps (0.1-0.2 secondes sur ma machine, enfin j'dis ça au pif mais c'est à peu près le temps que mon programme freeze à chaque requête) puis après ils restent presque inactif pendant 3-4 secondes (indépendamment de la machine).
J'avais pensé à faire un gros thread qui s'occupe de créer toutes les requêtes pour chaque objets de mon programme, mais je vois mal comment implémenter ça de manière propre sans foutre une variable global quelque part ![]()
Enfin bon, du coups j'vais opter pour faire un thread par onglet, ça reste le plus simple pour moi, merci ![]()
En C++, c'est quoi la meilleur méthode pour initialiser les valeurs par défaut d'une variable membre d'une classe ?
En supposant que la variable soit la même quelque soit le constructeur appelé, quelque soit les variables passé en paramètre etc etc, c'est quoi le mieux entre ces trois trucs :
class foo
{
int bar = 0;
};
foo::foo() : bar(0)
{
}
foo::foo()
{
bar = 0;
}
Comme ça je dirais le premier, mais j'ai jamais utilisé ça de ma vie (j'y ai juste jamais pensé) mais j'sais pas si ça fait "propre", même si en cherchant un peu sur internet c'est la solution la plus conseillée.
La premiere chose, je ne ais pas si ca fait ce que tu pense que ca fait.
En moyenne j'utilise la deuxieme parceque c'est la version qui garantie que l'initialisation se fait a la construction et pas une construction par defaut et une copie. (Dans le cas ou tu as des objets complexes.)
Nan le premier cas je sais pas vraiment ce qu'il se passe, le deuxième ça appelle le constructeur de l'objet bar quand le constructeur de l'objet foo est appelé, et le troisième c'est juste une assignation normale.
Le problème avec la deuxième méthode c'est que pour une dizaine de variable à initialiser c'est assez lourd et pas clair je trouve, l'avantage de la 1er méthode c'est que ça évite d'écrire des lignes inutiles comme dans la troisième et que pour plein de variable c'est plus clair que la deuxième, mais effectivement j'ai pas vraiment d'idée de ce qui se passe, donc si tu pouvais m'éclairer pour ce point ça m'arrangerais (je sais pas vraiment quoi chercher sur google pour trouver des infos là dessus) ![]()
ce que je dis dans ce post est à confirmer/vérifier, je suis pas certain à 100% (dans le sens où j'ai pas vu ça dans une doc officielle)
en C++ les int sont initialisé par défaut à 0, donc dans le cas 1
int bar = 0; et int bar; c'est pareil
par contre, si t'as un type non primitif à la place de int
la 2eme façon peut être indispensable dans le cas où tu souhaites spécifier un constructeur en particulier pour construire bar, si tu spécifies pas un constructeur dans la liste d'initialisation pour bar, ce sera le constructeur par défaut qui sera appelé
dans le 3eme cas, quoi que tu écrives dans le corps du constructeur, ce sera le constructeur par défaut de bar qui sera appelé
donc si tu veux un constructeur en particulier pour bar, il y a pas le choix, tu es obligé de le spécifier dans la liste d'initialisation
le reste ça change pas, seule différence c'est que la liste d'initialisation est exécuté avant la création de l'instance foo courante :
chaque attribut est crée à partir de la liste d'initialisation en appelant le constructeur spécifié pour chaque attribut, constructeur par défaut si aucun n'a été spécifié,
ensuite l'instance courante est crée
ensuite le corps du constructeur est exécuté
c'est pour ça qu'une fois arrivé dans le corps du constructeur, tu ne peux plus choisir la manière dont tes attributs sont construit, car ils ont déjà été crée avant d'entrée dans le corps du constructeur
ça peut être lisible la liste d'initialisation sinon, beaucoup font comme ça :
foo::foo()
: bar(0),
foobar(50),
trucmachin(60)
{
//
}
Le 29 janvier 2016 à 01:33:16 whiteapplex a écrit :
"en C++ les int sont initialisé par défaut à 0,"
Je suis pas convaincu
j'ai été confus, en fait c'est par défaut à 0 seulement pour les variables static
void foo()
{
int i;
std::cout << i;
}ça affichera bien 0, ce sera pas une garbage value comme ce serait le cas en C
mais dans le cas de variable non static dans une classe, oui ce sera une garbage value qui nécessite donc d'être initialisé
en C++ les int sont initialisé par défaut à 0
Nope. Voila un test simple.
erik@eriknewlaptop:/tmp$ cat foo.cpp
#include <iostream>
struct foo {
int a;
};
int main () {
foo bar;
if (bar.a < 0)
std::cout<<"blahhh!"<<std::endl;
return 0;
}
erik@eriknewlaptop:/tmp$ g++ -W -Wall foo.cpp -o foo
erik@eriknewlaptop:/tmp$ valgrind ./foo
==24198== Memcheck, a memory error detector
==24198== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==24198== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==24198== Command: ./foo
==24198==
==24198== Conditional jump or move depends on uninitialised value(s)
==24198== at 0x400853: main (in /tmp/foo)
==24198==
blahhh!
==24198==
==24198== HEAP SUMMARY:
==24198== in use at exit: 0 bytes in 0 blocks
==24198== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==24198==
==24198== All heap blocks were freed -- no leaks are possible
==24198==
==24198== For counts of detected and suppressed errors, rerun with: -v
==24198== Use --track-origins=yes to see where uninitialised values come from
==24198== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
erik@eriknewlaptop:/tmp$
A noter qu'un truc chiant avec les listes d'initialisation est qu'il faut lister les variable dans la liste dans l'ordre de declaration dans la classe. Oui c'est super casse couille et certain compilateur font des trucs bizarre si tu ne donne pas le bon ordre.
Je sais bien ce que la deuxième méthode et la troisième méthode font (du moins je pense savoir), c'est juste la première je sais pas exactement ce que ça fait, dans le doute je dirais que ça appel le constructeur qui prend en paramètre un int, du moins pour les types primitifs, mais après je sais pas ce qu'il se passe si on ré-initialise cette variable dans la liste d'initialisation du constructeur de la classe ![]()
Sinon ouais, mettre des retours à la ligne pour la liste d'initialisation ça rend le tout plus clair, mais c'pas très beau, enfin personnellement ce que je préfèrerais pouvoir utiliser c'est la 1er méthode, donner les valeurs par défaut dans la déclaration de la classe, mais je voudrais juste savoir si c'est bien propre de faire ça ![]()
http://pastebin.com/QKdDALDq
Le résultat étant :
test1
lol()6
test2
lol()5
C'est intéressant.
EDIT: Je me suis trompé dans le code, dans l'opérateur = en cout j'ai mis lol() au lieu de lol=, mais ça change rien vu que cet opérateur n'est jamais appelé.
godrik, j'ai précisé ce que j'ai dit dans mon post juste au dessus du tient
sinon bar.a est forcement negatif ? il peut être positif non?
C'est un coup de bol qu'il soit negatif. Ce qui est imoprtant le message de valgrind: "Conditional jump or move depends on uninitialised value(s)".
d’après le standard, c'est la même chose a part qu'un mem-initializer a la priorité.
http://ideone.com/Jvf3Pz
C'est vrai en C++ depuis C++11. Mais ca n'etait pas valide avant ou le =0 dans la declaration etait reserver pour les fonctions virtuelles pures. Donc bon c'est relativement recent, et plein d'environement n'ont pas de compilo C++11 standard. Perso, j'evite d'utiliser ces trucs la si c'est la seule feature de C++11 que j'utilise.
Perso j'utilise assez souvent les for range-based loop et les smart pointer, et le std::move du coups aussi, donc utiliser cette fonctionnalité là en plus c'est pas vraiment gênant pour moi ![]()
Du coups bah je pense que je vais utiliser ça la plupart du temps alors, merci ![]()
Bonjour,
Depuis quelques temps j'essaie de résoudre le problème des pokémons sur primers http://primers.xyz/3 mais je trouve pas le bon algo à appliquer, vers quoi je dois m'orienter pour commencer ? Merci
bluepoint_, techniquement ce que tu decrit c'est recherche locale gloutone et ce n'est pas un algorithme glouton (bien qu'il y a glouton dans le nom). Par definition, un algorithme glouton ne revient pas sur ces choix. Donc pour le probleme de tintinmage, l'algorithme glouton serait:
-a partir d'une equipe vide
-trouve le pokemon qui ameliore ton score le plus si tu l'ajoute a ton equipe
-recommence justqu'a ce que l'equipe soit complete
-renvoie cette equipe.
En fait, les algorithme glouton sont des cas particulier de programmation dynamique. Une programmation dynamique est gloutonne si tu peux trouver la decision optimale sans avoir a connaitre les valeure de la fonction pour des problemes plus simple. Ainsi il construit la solution optimale une decision a la fois en augmentant une decision partielle.
Les heuristiques gloutonnes sont constuites par analogie en disant que la decision que tu prends n'as pas a etre optimale et donc tu construis une solution en augmentant une decision partielle et en prenant la decision qui localement semble la meilleur.
(Et comme je sens qu'il y en a qui ne vont pas me contraire. source: cormen, chapitre algorithme glouton.)
Merci
50% de mes etudiants font cette erreur. C'est une classique.
Une autre de classique est de penser que n'importe quel algo qui memoize est de la programmation dynamique...
Le 30 janvier 2016 à 21:50:53 godrik a écrit :
50% de mes etudiants font cette erreur. C'est une classique.
Une autre de classique est de penser que n'importe quel algo qui memoize est de la programmation dynamique...
en même temps, pas mal de cours font l'erreur ou présente la programmation dynamique et la memoisation comme étant indissociable. dans le cours du MIT, il est carrément écrit dynamic programming = memoization + recursion. d'autres utilisent memoization pour dire top down (et tabulation pour bottom up).
dé les premières lignes du chapitre sur la prog dyn de introduction to algorithms, on peut lire
A dynamic-programming algorithm solves each
subsubproblem just once and then saves its answer in a table, thereby avoiding the
work of recomputing the answer every time it solves each subsubproblem.
the algorithm design manual (skiena), un autre livre réputé, dit
Dynamic programming combines the best of both worlds. It gives us a way to
design custom algorithms that systematically search all possibilities (thus guar-
anteeing correctness) while storing results to avoid recomputing (thus providing
efficiency). By storing the consequences of all possible decisions and using this
information in a systematic way, the total amount of work is minimized.[...]
Dynamic programming is a technique for efficiently implementing a recursive
algorithm by storing partial results. The trick is seeing whether the naive recursive
algorithm computes the same subproblems over and over and over again. If so,
storing the answer for each subproblems in a table to look up instead of recompute
can lead to an efficient algorithm[...]
Dynamic programming is essentially a tradeoff of space for time. Repeatedly re-
computing a given quantity is harmless unless the time spent doing so becomes
a drag on performance. Then we are better off storing the results of the initial
computation and looking them up instead of recomputing them again.
le seule livre (a ma connaissance) qui insiste bien sur la différence, c'est Models of computation (jeff erickson)
http://jeffe.cs.illinois.edu/teaching/algorithms/