OVH Cloud OVH Cloud

std::set

23 réponses
Avatar
Nicolas Aunai
salut,

je suis en train d'apprendre les conteneurs de la stl, et dans quel cas
utiliser l'un plutôt que l'autre... j'ai un petit problème a vous
soumettre.

Disons que j'ai un objet A qui contient un string et un ensemble
ordonné de pointeurs sur des objets A.

pour cet ensemble ordonné, j'utilise std::set, qui me permet d'ajouter
des éléments qui sont inséré directement au bon endroit selon la
relation d'ordre définie pour A.

maintenant j'ai quelques problèmes :

class MaString
{
public:
string s;
set<const MaString *> tab;


MaString(const string &str);
void MiseAJour(const vector<MaString> &);
static void maj(vector<MaString> &);
bool operator<(const MaString &ms) const;
friend ostream & operator<<(ostream &os,const MaString &ms);
};

le vector<MaString> pris en argument par MiseAjour contient tout un tas
d'objet MaString non ordonnés, dont l'objet en cours lui même, et le
set de l'objet, doit se remplir avec les pointeurs vers les autres
objets du vector, sauf bien sûr le pointeur sur lui même. Et les
pointeurs doivent etre rangés selon la relation d'ordre de MaString.

(la relation d'ordre de MaString est tout simplement l'opérateur '<' de
son membre string)

j'ai essayé ceci :

void
MaString::MiseAJour(const vector<MaString> &s)
{
vector<MaString>::const_iterator iter_s = s.begin();

while(iter_s != s.end())
{
if(&*iter_s != this)
tab.insert(&*iter_s);
}
}


je n'ai pas l'impression que ça marche correctement, de plus, la
méthode 'insert' doit renvoyer un objet 'pair<iterator,bool>' indiquant
si l'insertion a bien eu lieu, si j'ai bien compris. Mais je pige pas
trop ce qu'est cet objet, ni comment le déclarer pour vérifier le
retour de insert.


maintenant autre question, les set ne disposent pas de l'opérateur []
pour accéder a un de leurs membres, ou alors j'ai pas vu pas
compris...? donc le moyen pour aller sur un objet d'un set et
l'iterateur... je m'en sert pour ma surcharge d'affichage de mon objet
MaString, mais apparement j'ai une faute sur l'iterator, et je
comprends pas


ostream &
operator<<(ostream &os,const MaString &ms)
{
set<const MaString*>::const_iterator i = ms.tab.begin();

os << "String = " << ms.s << endl << endl;

os << "Mes Voisins ( "<< ms.tab.size() << " ): " << endl;
os << "============= " << endl << endl;

while(i != ms.tab.end())
{
os << " - "<< *i->s << endl;
i ++;
}
os << endl;

return os;
}

--
Nico,
http://astrosurf.com/nicoastro
messenger : nicolas_aunai@hotmail.com

10 réponses

1 2 3
Avatar
Nicolas Aunai
Franck Branjonneau avait énoncé :


C'est un peu confus.


c'est pas simple a expliquer sans en dire des tonnes aussi...

pair<set<const Cluster*>::iterator,bool> p;
[...]
p = Influences.insert(&*i);//devrait insérer au bon endroit


Comme p est utilisé comme resultat de Influences.insert j'en déduis
que le type de Influences -- ou un de ses types de base -- est
set<const Cluster*>. Il suit que le tri est fait avec std::less< const
Cluster* >::operator() qui, par défaut, va ordonner les pointeurs.



désolé j'aurai du mettre la déclaration du set :

set<const Cluster *,CompareDistance> Influences;
avec le foncteur CompareDistance :

class CompareDistance
{
private:
const Cluster *p;

public:
CompareDistance(const Cluster &c);
bool operator()(const Cluster *c1, const Cluster *c2) const;
};

CompareDistance::CompareDistance(const Cluster &c)
:p(&c)
{
}

bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


et tout ça, en fait je viens de me rendre compte que ça marche très
bien pour n cluster dans u vector simple...
voyez plutot :



system[0] :
======================================= Position : [ 0, 0, 0 ]
Mes influences :
----------------
-Position : [ 1, 2, 3 ] D = 3.742
-Position : [ 4, 5, 6 ] D = 8.775
-Position : [ 7, 7, 2 ] D = 10.1
-Position : [ 10, 92, 12 ] D = 93.32
========================================

system[1] :
======================================= Position : [ 7, 7, 2 ]
Mes influences :
----------------
-Position : [ 4, 5, 6 ] D = 5.385
-Position : [ 1, 2, 3 ] D = 7.874
-Position : [ 0, 0, 0 ] D = 10.1
-Position : [ 10, 92, 12 ] D = 85.64
========================================

system[2] :
======================================= Position : [ 10, 92, 12 ]
Mes influences :
----------------
-Position : [ 7, 7, 2 ] D = 85.64
-Position : [ 4, 5, 6 ] D = 87.41
-Position : [ 1, 2, 3 ] D = 90.9
-Position : [ 0, 0, 0 ] D = 93.32
========================================

system[3] :
======================================= Position : [ 1, 2, 3 ]
Mes influences :
----------------
-Position : [ 0, 0, 0 ] D = 3.742
-Position : [ 4, 5, 6 ] D = 5.196
-Position : [ 7, 7, 2 ] D = 7.874
-Position : [ 10, 92, 12 ] D = 90.9
========================================

system[4] :
======================================= Position : [ 4, 5, 6 ]
Mes influences :
----------------
-Position : [ 1, 2, 3 ] D = 5.196
-Position : [ 7, 7, 2 ] D = 5.385
-Position : [ 0, 0, 0 ] D = 8.775
-Position : [ 10, 92, 12 ] D = 87.41
========================================



si maintenant j'utilise ma classe Systeme pour ranger mes clusters ça
merdouille... je vois pas pk... mais bon là je peux pas tout vous
expliquer y'a donc que moi qui peut trouver l'erreur... qui demeure
pour l'instant un mystère...

au moins je sais que ça vient pas du tri sur mon set.

--
Nico,
http://astrosurf.com/nicoastro
messenger :


Avatar
Franck Branjonneau
Nicolas Aunai écrivait:

Franck Branjonneau avait énoncé :


C'est un peu confus.


c'est pas simple a expliquer sans en dire des tonnes aussi...


S'astreindre à être clair et concis, c'est souvent se poser les bonnes
questions et, trouver les réponses ;-)

désolé j'aurai du mettre la déclaration du set :

set<const Cluster *,CompareDistance> Influences;


C'est un membre du type Cluster ? Quand et comment est-il initialisé ?

avec le foncteur CompareDistance :

class CompareDistance
{
private:
const Cluster *p;

public:
CompareDistance(const Cluster &c);
bool operator()(const Cluster *c1, const Cluster *c2) const;
};

CompareDistance::CompareDistance(const Cluster &c)
:p(&c)
{
}


Semble correct.

bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


Attention, les résultats qui suivent laissent à penser que
Cluster::Distance retourne un type réel que se passe-t-il si les
distances des clusters pointés par c1 et c2 au cluster pointé par p
sont proches ?

et tout ça, en fait je viens de me rendre compte que ça marche très
bien pour n cluster dans u vector simple...


Conclusion ? Quand et comment Influences est-il initialisé ?

--
Franck Branjonneau


Avatar
Nicolas Aunai
Franck Branjonneau a formulé ce dimanche :


set<const Cluster *,CompareDistance> Influences;


C'est un membre du type Cluster ? Quand et comment est-il initialisé ?


dans le constructeur de cluster :


Cluster::Cluster(const double a,
const double b,
const double c,
const unsigned int gen)
:Position(a,b,c),Influences(CompareDistance(*this)),Fils(),Generation(gen)
{
Parent = NULL; //pas de parent lors de sa construction
}



bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


Attention, les résultats qui suivent laissent à penser que
Cluster::Distance retourne un type réel que se passe-t-il si les
distances des clusters pointés par c1 et c2 au cluster pointé par p
sont proches ?



double Distance(const Cluster &c) const;
les distances par rapport a p qui est l'objet courant en fait, sont
comparées et ensuite insérées dans le set.

--
Nico,
http://astrosurf.com/nicoastro
messenger :


Avatar
Franck Branjonneau
Nicolas Aunai icrivait:

Franck Branjonneau a formulé ce dimanche :


set<const Cluster *,CompareDistance> Influences;


C'est un membre du type Cluster ? Quand et comment est-il initialisé ?


dans le constructeur de cluster :


Cluster::Cluster(const double a,
const double b,
const double c,
const unsigned int gen)
:Position(a,b,c),Influences(CompareDistance(*this)),Fils(),Generation(gen)


Tes instances de CompareDistance sont initialisées avec un pointeur
this qui est invalidé quand ton système, ton std::vector de Cluster,
est redimensionné.

{
Parent = NULL; //pas de parent lors de sa construction
}


Pourquoi tu n'ajoutes pas Parent à ta liste d'initialisation ?

bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


Attention, les résultats qui suivent laissent à penser que
Cluster::Distance retourne un type réel que se passe-t-il si les
distances des clusters pointés par c1 et c2 au cluster pointé par p
sont proches ?



double Distance(const Cluster &c) const;
les distances par rapport a p qui est l'objet courant en fait, sont
comparées et ensuite insérées dans le set.


J'avais compris. L'objet de ma question est de te faire
remarquer que le type double à les limites de sa représentation.

--
Franck Branjonneau



Avatar
Falk Tannhäuser
Franck Branjonneau wrote:
Nicolas Aunai icrivait:
Cluster::Cluster(const double a,
const double b,
const double c,
const unsigned int gen)
:Position(a,b,c),Influences(CompareDistance(*this)),Fils(),Generation(gen)


Tes instances de CompareDistance sont initialisées avec un pointeur
this qui est invalidé quand ton système, ton std::vector de Cluster,
est redimensionné.
À priori ça ne pose pas de problème car la durée de vie de 'Influences'

qui est un membre de 'Cluster' du type 'set<Cluster const*, CompareDistance>'
et qui détiendra une instance de 'CompareDistance' avec un pointeur 'this',
ne dépasse pas la durée de vie de l'objet 'Cluster' désigné par '*this'.

Deux choses qui peuvent poser problème :
* 'Influences' stocke des pointeurs sur d'autres instances de 'Cluster'
et ces instances n'ont pas forcement la même durée de vie que l'instance
désignée par '*this' (par exemple suite au rédimensionnement du 'vector').
Solution possible : Stocker des pointeurs sur 'Cluster' dans le 'vector'
et gérer proprement la durée de vie des instances de 'Cluster' ;
être sûr que tous les pointeurs sur une instance de 'Cluster' donnée
soient enlevés de tous les 'Influences' avant sa destruction
* La relation d'ordre servant à déterminer l'endroit d'insertion d'un
élément dans un 'set' ne doit pas changer "à la volée" sinon ça risque
de faire désordre... Es-tu sûr que les coordonnées de ton 'Cluster'
(apparemment le champ 'Position' comportant trois 'double' ?) ne
varie pas pendant la durée de vie de ton objet ? Le mieux est de
déclarer ce champ 'const' ce qui empêchera entre autres l'affectation
de 'Cluster' (et par conséquence l'instantiation de 'std::vector<Cluster>',
solution : voir ci-dessus)

bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


Attention, les résultats qui suivent laissent à penser que
Cluster::Distance retourne un type réel que se passe-t-il si les
distances des clusters pointés par c1 et c2 au cluster pointé par p
sont proches ?



double Distance(const Cluster &c) const;
les distances par rapport a p qui est l'objet courant en fait, sont
comparées et ensuite insérées dans le set.


J'avais compris. L'objet de ma question est de te faire
remarquer que le type double à les limites de sa représentation.
Effectivement. Par exemple, les points [ 8, 2, 4.1 ] et [ 1, 1, 9.1 ]

ont la même distance sqrt(84.81) au point [ 0, 0, 0 ] en arithmétique
exacte, mais avec mon compilateur (gcc 3.3.1 i686-pc-cygwin) j'obtiens
une différence de 7.71952e-16 entre les deux distances avec des 'double'.

Par contre, si deux points ont exactement la même distance à un point donné en
"arithmétique flottante de la machine" (ce qui devrait être le cas, par exemple,
pour [ 1, 2, 10 ] et[ -4, 5, 8 ] au point [ 0, 0, 0 ]), 'std::set' le gardera
que le premier inséré. D'où mon conseil dans l'autre post de regarder plutôt
'std::multiset'.

Falk




Avatar
Falk Tannhäuser
Franck Branjonneau wrote:
Nicolas Aunai icrivait:
Cluster::Cluster(const double a,
const double b,
const double c,
const unsigned int gen)
:Position(a,b,c),Influences(CompareDistance(*this)),Fils(),Generation(gen)


Tes instances de CompareDistance sont initialisées avec un pointeur
this qui est invalidé quand ton système, ton std::vector de Cluster,
est redimensionné.
À priori ça ne pose pas de problème car la durée de vie de 'Influences'

qui est un membre de 'Cluster' du type 'set<Cluster const*, CompareDistance>'
et qui détiendra une instance de 'CompareDistance' avec un pointeur 'this',
ne dépasse pas la durée de vie de l'objet 'Cluster' désigné par '*this'.

Deux choses qui peuvent poser problème :
* 'Influences' stocke des pointeurs sur d'autres instances de 'Cluster'
et ces instances n'ont pas forcement la même durée de vie que l'instance
désignée par '*this' (par exemple suite au rédimensionnement du 'vector').
Solution possible : Stocker des pointeurs sur 'Cluster' dans le 'vector'
et gérer proprement la durée de vie des instances de 'Cluster' ;
être sûr que tous les pointeurs sur une instance de 'Cluster' donnée
soient enlevés de tous les 'Influences' avant sa destruction
* La relation d'ordre servant à déterminer l'endroit d'insertion d'un
élément dans un 'set' ne doit pas changer "à la volée" sinon ça risque
de faire désordre... Es-tu sûr que les coordonnées de ton 'Cluster'
(apparemment le champ 'Position' comportant trois 'double' ?) ne
varient pas pendant la durée de vie de ton objet ? Le mieux est de
déclarer ce champ 'const' ce qui empêchera entre autres l'affectation
de 'Cluster' (et par conséquence l'instantiation de 'std::vector<Cluster>',
solution : voir ci-dessus)

bool
CompareDistance::operator()(const Cluster *c1, const Cluster *c2) const
{
return c1->Distance(*p) < c2->Distance(*p);
}


Attention, les résultats qui suivent laissent à penser que
Cluster::Distance retourne un type réel que se passe-t-il si les
distances des clusters pointés par c1 et c2 au cluster pointé par p
sont proches ?



double Distance(const Cluster &c) const;
les distances par rapport a p qui est l'objet courant en fait, sont
comparées et ensuite insérées dans le set.


J'avais compris. L'objet de ma question est de te faire
remarquer que le type double à les limites de sa représentation.
Effectivement. Par exemple, les points [ 8, 2, 4.1 ] et [ 1, 1, 9.1 ]

ont la même distance sqrt(84.81) au point [ 0, 0, 0 ] en arithmétique
exacte, mais avec mon compilateur (gcc 3.3.1 i686-pc-cygwin) j'obtiens
une différence de 7.71952e-16 entre les deux distances avec des 'double'.

Par contre, si deux points ont exactement la même distance à un point donné en
"arithmétique flottante de la machine" (ce qui devrait être le cas, par exemple,
pour [ 1, 2, 10 ] et[ -4, 5, 8 ] au point [ 0, 0, 0 ]), 'std::set' ne gardera
que le premier inséré. D'où mon conseil dans l'autre post de regarder plutôt
'std::multiset'.

Falk




Avatar
Nicolas Aunai



À priori ça ne pose pas de problème car la durée de vie de 'Influences'
qui est un membre de 'Cluster' du type 'set<Cluster const*, CompareDistance>'
et qui détiendra une instance de 'CompareDistance' avec un pointeur 'this',
ne dépasse pas la durée de vie de l'objet 'Cluster' désigné par '*this'.



Deux choses qui peuvent poser problème :
* 'Influences' stocke des pointeurs sur d'autres instances de 'Cluster'
et ces instances n'ont pas forcement la même durée de vie que l'instance
désignée par '*this' (par exemple suite au rédimensionnement du 'vector').
Solution possible : Stocker des pointeurs sur 'Cluster' dans le 'vector'
et gérer proprement la durée de vie des instances de 'Cluster' ;
être sûr que tous les pointeurs sur une instance de 'Cluster' donnée
soient enlevés de tous les 'Influences' avant sa destruction

* La relation d'ordre servant à déterminer l'endroit d'insertion d'un
élément dans un 'set' ne doit pas changer "à la volée" sinon ça risque
de faire désordre... Es-tu sûr que les coordonnées de ton 'Cluster'
(apparemment le champ 'Position' comportant trois 'double' ?) ne
varient pas pendant la durée de vie de ton objet ? Le mieux est de
déclarer ce champ 'const' ce qui empêchera entre autres l'affectation
de 'Cluster' (et par conséquence l'instantiation de 'std::vector<Cluster>',
solution : voir ci-dessus)



c'est sûr que ça n'est pas ça, la position d'un cluster est symbolisée
par un objet V3D qui est lui même l'encapsulation de trois doubles en
effet... et les positions ne changent pas.
par contre pas moyen de mettre ce champ en 'const', car le but de la
manoeuvre est de faire un ensemble dynamique de points et donc que la
position de chacun change... à chaque changement, les influences des
cluster sont totalement refaites, et pendant cette mise à jour la
position ne change pas.




Effectivement. Par exemple, les points [ 8, 2, 4.1 ] et [ 1, 1, 9.1 ]
ont la même distance sqrt(84.81) au point [ 0, 0, 0 ] en arithmétique
exacte, mais avec mon compilateur (gcc 3.3.1 i686-pc-cygwin) j'obtiens
une différence de 7.71952e-16 entre les deux distances avec des 'double'.

Par contre, si deux points ont exactement la même distance à un point donné
en "arithmétique flottante de la machine" (ce qui devrait être le cas, par
exemple, pour [ 1, 2, 10 ] et[ -4, 5, 8 ] au point [ 0, 0, 0 ]), 'std::set'
ne gardera que le premier inséré. D'où mon conseil dans l'autre post de
regarder plutôt 'std::multiset'.



bon bref... là n'est pas le problème je pense puisque le tri marche
parfaitement si j'utilise uniquement ma classe cluster et un vector
simple au lieu de mon systeme.

je mets une version du code qui marche ici :
http://nicolas.aunai.free.fr/particule/points/ok
c'est compilable et ça représente juste un vector de cluster... on
constate que le tri se fait bien...

maintenant, je remplace le vector de cluster par ma classe Systeme (qui
n'est pas super bien faite mais bon... doit y avoir une erreur sinon ça
marcherai)

et le code est là :
http://nicolas.aunai.free.fr/particule/points/paok

voila, tout ceci montre que l'erreur se trouve vraissemblablement dans
la classe systeme car son utilisation vient foutre ce comportement
bizarre qui 'était pas là avec le simple vector du test de cluster...


en espérant pas trop faire ch*** :) merci de votre aide

a+

--
Nico,
http://astrosurf.com/nicoastro
messenger :

Avatar
Falk Tannhäuser
Nicolas Aunai wrote:
Effectivement. Par exemple, les points [ 8, 2, 4.1 ] et [ 1, 1, 9.1 ]
ont la même distance sqrt(84.81) au point [ 0, 0, 0 ] en arithmétique
exacte, mais avec mon compilateur (gcc 3.3.1 i686-pc-cygwin) j'obtiens
une différence de 7.71952e-16 entre les deux distances avec des 'double'.

Par contre, si deux points ont exactement la même distance à un point
donné en "arithmétique flottante de la machine" (ce qui devrait être
le cas, par exemple, pour [ 1, 2, 10 ] et[ -4, 5, 8 ] au point [ 0, 0,
0 ]), 'std::set' ne gardera que le premier inséré. D'où mon conseil
dans l'autre post de regarder plutôt 'std::multiset'.
bon bref... là n'est pas le problème je pense puisque le tri marche

parfaitement si j'utilise uniquement ma classe cluster et un vector
simple au lieu de mon systeme.
En mettant

s3.AjouterCluster(Cluster(1,2,10));
s3.AjouterCluster(Cluster(-4,5,8));
s3.AjouterCluster(Cluster(0,0,0));
dans ton 'main', le programme m?affiche
[...]
cluster 2 :
======================================= Position : [ 0, 0, 0 ]
barycentre : [ 0, 0, 0 ]
Generation : 1
Mes fils :
----------
Mes influences :
----------------
-Position : [ 1, 2, 10 ] D = 10.25
========================================
(absence de "-Position : [ -4, 5, 8 ] D = 10.25" ; je ne sais pas si c?est
important ou pas pour ce que tu veux faire - sinon voir 'std::multiset')


je mets une version du code qui marche ici :
http://nicolas.aunai.free.fr/particule/points/ok
c'est compilable et ça représente juste un vector de cluster... on
constate que le tri se fait bien...

maintenant, je remplace le vector de cluster par ma classe Systeme (qui
n'est pas super bien faite mais bon... doit y avoir une erreur sinon ça
marcherai)

et le code est là :
http://nicolas.aunai.free.fr/particule/points/paok

voila, tout ceci montre que l'erreur se trouve vraissemblablement dans
la classe systeme car son utilisation vient foutre ce comportement
bizarre qui 'était pas là avec le simple vector du test de cluster...
Le problème vient du fait que 'std::vector' a besoin du constructeur de

copie et de l?opérateur d?affectation, et ta classe 'Cluster' utilise
les opérations générées par le compilateur qui ne marchent pas bien parce
que le champ ?Influences? aura un functeur de comparaison pointant sur
le 'Cluster' d?origine plutôt que l?objet courant. Par conséquent,
les distances à l?insertion sont calculées par rapport à ce premier...
En mettant

Cluster::Cluster(Cluster const& c)
: Position(c.Position),
Influences(c.Influences.begin(), c.Influences.end(), CompareDistance(*this)),
Parent(c.Parent),
Generation(c.Generation)
{
}

Cluster& Cluster::operator=(Cluster const& c)
{
Position = c.Position;
Influences.clear();
Influences.insert(c.Influences.begin(), c.Influences.end());
Parent = c.Parent;
Generation = c.Generation;
return *this;
}

cela se passe mieux.

Reste la question si la classe 'Cluster' doit réellement avoir une sémantique
de valeur ou s?il faut en interdire les opérations de copie (ce qui obligerait
entre autres de remplacer 'std::vector<Cluster>' par 'std::vector<Cluster*>').

À plus
Falk


Avatar
Franck Branjonneau
Falk Tannhäuser écrivait:

Franck Branjonneau wrote:

Nicolas Aunai écrivait:

Cluster::Cluster(const double a,
const double b,
const double c,
const unsigned int gen)
:Position(a,b,c),Influences(CompareDistance(*this)),Fils(),Generation(gen)


Tes instances de CompareDistance sont initialisées avec un pointeur
this qui est invalidé quand ton système, ton std::vector de Cluster,
est redimensionné.


À priori ça ne pose pas de problème car la durée de vie de
'Influences' qui est un membre de 'Cluster' du type 'set<Cluster
const*, CompareDistance>' et qui détiendra une instance de
'CompareDistance' avec un pointeur 'this', ne dépasse pas la durée
de vie de l'objet 'Cluster' désigné par
'*this'.



A posteriori c'est encore pire : les éléments du vecteur sont des
*copies* d'instances de Cluster.

std::vector< Cluster > systeme;

{
Cluster cluster; // ici cluster.Influences.key_comp().p est &cluster.
systeme.push_back(cluster); // ici system[0].Influences.key_comp().p est &cluster

} // ici system[0].Influences.key_comp().p est invalide.

Deux choses qui peuvent poser problème :
* 'Influences' stocke des pointeurs sur d'autres instances de
'Cluster' et ces instances n'ont pas forcement la même durée de vie
que l'instance désignée par '*this' (par exemple suite au
rédimensionnement du 'vector').


Regarde Cluster::maj_influences(const vector<Cluster> &t) donné par le
PO : ce n'est pas le cas.

Solution possible : Stocker des pointeurs sur 'Cluster' dans le
'vector' et gérer proprement la durée de vie des instances de
'Cluster' ;


Un std::vector gére proprement la durée de vie de ses instances. La
seule précaution à prendre est de le construire entièrement avant
d'utiliser les adresses de ses éléments.

être sûr que tous les pointeurs sur une instance de 'Cluster'
donnée soient enlevés de tous les 'Influences' avant sa
destruction


Extrait de la fonction sus-citée ;-) :
Influences.clear(); //efface les influences pour refaire...
--
Franck Branjonneau



Avatar
Franck Branjonneau
Falk Tannhäuser écrivait:

Nicolas Aunai wrote:

je mets une version du code qui marche ici :
http://nicolas.aunai.free.fr/particule/points/ok

(qui n'est pas super bien faite mais bon... doit y avoir une erreur
sinon ça marcherai) et le code est là :
http://nicolas.aunai.free.fr/particule/points/paok


Le problème vient du fait que 'std::vector' a besoin du constructeur
de copie et de l?opérateur d?affectation, et ta classe 'Cluster'
utilise les opérations générées par le compilateur qui ne marchent
pas bien parce que le champ ?Influences? aura un functeur de
comparaison pointant sur le 'Cluster' d?origine plutôt que l?objet
courant. Par conséquent, les distances à l?insertion sont calculées
par rapport à ce premier...


Oui.

En mettant

Cluster::Cluster(Cluster const& c)
: Position(c.Position),
Influences(c.Influences.begin(), c.Influences.end(), CompareDistance(*this)),
Parent(c.Parent),
Generation(c.Generation)
{
}

Cluster& Cluster::operator=(Cluster const& c)
{
Position = c.Position;
Influences.clear();
Influences.insert(c.Influences.begin(), c.Influences.end());
Parent = c.Parent;
Generation = c.Generation;
return *this;
}

cela se passe mieux.


Une autre solution, qui évite le constructeur de copie et l'opérateur
d'affectation est de modifier CompareDistance pour ne garder que
l'information utile :

class CompareDistance
{
private:
// const Cluster *p;
V3D position_;

public:
CompareDistance(const Cluster &c);
bool operator()(const Cluster *c1, const Cluster *c2) const;
};

Reste la question si la classe 'Cluster' doit réellement avoir une
sémantique de valeur ou s?il faut en interdire les opérations de
copie (ce qui obligerait entre autres de remplacer
'std::vector<Cluster>' par 'std::vector<Cluster*>').


Le main() de Nicolas est en O(n^2 ln n) ou n est la taille d'un
std::vector<Cluster>. N'est-ce pas un début de réponse ?
--
Franck Branjonneau


1 2 3