OVH Cloud OVH Cloud

Recopier un vecteur de pointeurs

7 réponses
Avatar
Pierre THIERRY
Bonjour à tous,

j'ai un vecteur de pointeurs sur des instances de dérivées d'une même
classe de base

vector<Foo*> vec1;

Ce qui me permet d'utiliser une fonction virtuelle de la classe Foo

vector<Foo*>::iterator it;
...
(*it)->bar();

Et j'aimerais faire une copie vec2 de ce vec1, dont les pointeurs
pointeraient sur des copies des objets pointés dans vec1. Si je fais une
simple compie de vec1, je me retrouve avec des objets pointés deux fois,
d'où risque de modification et, pire, d'utilisation de delete plusieurs
fois.

Je ne vois pas du tout comment réaliser une copie de l'objet pointé. Si
je le déréférence pour créer un objet, il faudra bien que je donne
explicitement un type, donc celui de la classe de base, et je perds ses
caractéristiques

Foo *new_ptr = Foo(*(*it))

Quelqu'un a déjà rencontré ça, ou voit comment ce serait possible ?

Laborieusement,
Nowhere man

--
nowhere.man@levallois.eu.org
OpenPGP 0xD9D50D8A

7 réponses

Avatar
Rémy
"Pierre THIERRY" a écrit dans le message de
news:
Bonjour à tous,

j'ai un vecteur de pointeurs sur des instances de dérivées d'une même
classe de base

vector<Foo*> vec1;

Ce qui me permet d'utiliser une fonction virtuelle de la classe Foo

vector<Foo*>::iterator it;
...
(*it)->bar();

Et j'aimerais faire une copie vec2 de ce vec1, dont les pointeurs
pointeraient sur des copies des objets pointés dans vec1. Si je fais une
simple compie de vec1, je me retrouve avec des objets pointés deux fois,
d'où risque de modification et, pire, d'utilisation de delete plusieurs
fois.

Je ne vois pas du tout comment réaliser une copie de l'objet pointé. Si
je le déréférence pour créer un objet, il faudra bien que je donne
explicitement un type, donc celui de la classe de base, et je perds ses
caractéristiques

Foo *new_ptr = Foo(*(*it))

Quelqu'un a déjà rencontré ça, ou voit comment ce serait possible ?

Laborieusement,
Nowhere man

--

OpenPGP 0xD9D50D8A



Bonjour,

Une solution est d'implémenter dans chaque classe une méthode (virtuelle)
Clone qui fait une copie de l'objet courant (elle connait la classe).

La copie de chaque objet se fait par
Foo *new_ptr = it->Clone();

Rémy

Avatar
Pierre THIERRY
Le Mon, 02 May 2005 16:35:48 +0200, Rémy a écrit :
Une solution est d'implémenter dans chaque classe une méthode
(virtuelle) Clone qui fait une copie de l'objet courant (elle connait
la classe).


J'y ai également pensé après avoir posté mon article, en me baladant
(c'est pour éviter de perdre ce genre d'idées que j'ai un dictaphone
numérique ;-) )... Pour l'instant, c'est la seule solution qui me
vienne, mais je trouve ça insatisfaisant.

Ce qui est con, c'est que clone se résumé à ça :

virtual Classe* clone() const { return new Classe(*this); }

C'est-à-dire qu'il faudrait simplement une sorte de template
automatique...

Dubitativement,
Nowhere man
--

OpenPGP 0xD9D50D8A

Avatar
Michel Michaud
Dans le message ,
Ce qui est con, c'est que clone se résumé à ça :

virtual Classe* clone() const { return new Classe(*this); }

C'est-à-dire qu'il faudrait simplement une sorte de template
automatique...


Recherche les articles « Copie de classe dérivée » au début d'avril.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar
Pierre THIERRY
Le Mon, 02 May 2005 16:31:55 -0400, Michel Michaud a écrit :
Recherche les articles « Copie de classe dérivée » au début d'avril.


Je vais voir ça.

Pour l'instant, je m'en tire avec ceci dans  :

class Base {
template<class T> T* clone() const
{
return new T(*this);
}
virtual Base* clone() const;
}

Et je n'ai plus qu'à mettre le prototype dans les dérivées, ce qui me
satisfait, finalement (ce qui me faisait chier, c'est de réécrire X fois
la même fonction, ça me démange) :

class Derivee {
virtual Derivee* clone() const;
}

Brièvement,
Nowhere man
--

OpenPGP 0xD9D50D8A

Avatar
kanze
Pierre THIERRY wrote:
Recherche les articles « Copie de classe dérivée » au début
d'avril.


Je vais voir ça.

Pour l'instant, je m'en tire avec ceci dans :

class Base {
template<class T> T* clone() const
{
return new T(*this);
}
virtual Base* clone() const;
}

Et je n'ai plus qu'à mettre le prototype dans les dérivées, ce
qui me satisfait, finalement (ce qui me faisait chier, c'est
de réécrire X fois la même fonction, ça me démange) :

class Derivee {
virtual Derivee* clone() const;
}


Et ça marche comment ?

Moi, j'réécris la fonction. Elle n'est pas longue ; je le trouve
moins fastidieux à le réécrire que de dériver d'une classe
template supplémentaire. Ceci dit, c'est facile à oublier. C'est
pour ça qu'en général, la fonction publique dans la classe de
base ne serait pas virtuelle, mais ressemblerait à :

Base* Base::clone() const
{
Base* result = doClone() ;
assert( typeid( *result ) == typeid( *this ) ) ;
return result ;
}

Avec une fonction virtuelle privée doClone() qui fait le new.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Pierre THIERRY
Le Tue, 03 May 2005 01:37:53 +0200, Pierre THIERRY a écrit :
Pour l'instant, je m'en tire avec ceci dans  :

class Base {
template<class T> T* clone() const
{
return new T(*this);
}
virtual Base* clone() const;
}

Et je n'ai plus qu'à mettre le prototype dans les dérivées,


J'ai crié victoire trop tôt : ça compile bien, mais ça foire
lamentablement à l'édition des liens... :-/

Pour l'instant, j'ai donc X fois la même définition, à la main. Celui
qui trouve un moyen vraiment élégant aura ma reconnaissance éternelle.

Manuellement,
Nowhere man
--

OpenPGP 0xD9D50D8A

Avatar
Pierre THIERRY
Le Tue, 03 May 2005 03:03:22 -0700, kanze a écrit :
Et ça marche comment ?


Mal. Cf. mon autre post. :-/

Base* Base::clone() const
{
Base* result = doClone() ;
assert( typeid( *result ) == typeid( *this ) ) ;
return result ;
}


Je pense que je vais rajouter quelque chose comme ça, mais plutôt avec
une exception qu'un assert.

Exeptionnellement,
Nowhere man
--

OpenPGP 0xD9D50D8A