OVH Cloud OVH Cloud

std::vector copy constructor

34 réponses
Avatar
Cyrille \cns\ Szymanski
Est-il possible d'utiliser std::vector de telle sorte que les appels à
resize construisent chaque objet plutôt que d'utiliser un copy
constructor ?

L'idée est d'avoir un fonctionnement similaire à celui du code suivant
mais en évitant la copie de l'objet et le gâchis de mémoire :

vector<MyClass> vec;
vec.reserve(20);
for( int i=0; i<10; ++i )
{
vec.push_back( *(new MyClass()) );
}

A défaut, quelle est la façon propre de faire un
// construire l'objet
MyClass *tmp = new MyClass();
// le placer dans le tableau
vec.push_back( *tmp );
// limérer la mémoire sans appeler le destructeur
free( tmp );

Je veux bien fournir mon propre copy constructor et lui faire créer un
nouvel objet de toutes pièces, mais cela est d'une part détourner son
vrai objectif et d'autre part cela risque d'interférer avec les vraies
copies d'objet.

--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/

10 réponses

1 2 3 4
Avatar
Christophe Lephay
"Cyrille "cns" Szymanski" a écrit dans le message de
news:
Comment créer un tableau d'objets qui ne sont pas des copies d'un objet
de départ.


Tu ne peux pas.

Chris

Avatar
Christophe de Vienne
Cyrille "cns" Szymanski wrote:

En lisant tes différents posts, je me demande si ce n'est pas tout
simplement un vecteur de pointeur (intelligent éventuellement) qu'il te
faut : Les instances ne seront pas copiés, comme tu le souhaites.


Merci on me comprend !!!
Exactement, sauf que je désire avoir un acces direct aux objets. Vu que
tous mes objets ont la même taille, c'est un job idéal pour un tableau. Un
MyClass[] est quand même beaucoup plus performant qu'un *MyClass[].



Mais ne pas copier tes instances n'est pas forcément moins performant que ce
que tu suggères. Dans un fil de discussion récent le sujet est abordé.

Pour résumer, instancier un objet sur la pile puis le copier dans un
emplacement déjà alloué (comme c'est le cas avec le reserve() de vector),
peut s'avérer plus rapide qu'un new qui lui fait un appel système pour
allouer de la mémoire.
Ce que tu veux donc, c'est :

std::vector<MyClass> v;

for(int i = 0; i != 10; ++i)
{
v.push_back( MyClass() ); // l'objet temporaire est alloué sur la pile.
}

En espérant que ça t'aide, et aussi ne pas avoir dit trop de bêtise...

A+


Christophe

--
Christophe de Vienne
Experience is something you don't get until just after you need it.
Oliver's Law.


Avatar
Cyrille \cns\ Szymanski
Comment créer un tableau d'objets qui ne sont pas des copies d'un objet
de départ.


Tu ne peux pas.


Je veux donc je peux :-)

C'est juste que la template vector ne me sera peut-être pas d'un grand
seours.

--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/


Avatar
Cyrille \cns\ Szymanski
Mais ne pas copier tes instances n'est pas forcément moins performant
que ce que tu suggères. Dans un fil de discussion récent le sujet est
abordé.


Références ?


Pour résumer, instancier un objet sur la pile puis le copier dans un
emplacement déjà alloué (comme c'est le cas avec le reserve() de
vector), peut s'avérer plus rapide qu'un new qui lui fait un appel
système pour allouer de la mémoire.

Ce que tu veux donc, c'est :


Ce que je veux c'est dynamiquement allouer de la mémoire (un tableau de n
objets, malloc( sizeof(MyClass)*n ) ) et instancier un objet à chaque
emplacement (new (&vec[i]) MyClass()) ce qui est a mon avis un moyen
assez performant pour instancier n objets et pouvoir y accéder rapidement
ensuite.

Vous me direz que MyClass[] est là pour ça, mais en fait non car le
tableau serait de taille fixe et je dois pouvoir ajouter et supprimer des
objets à ma guise.


v.push_back( MyClass() ); // l'objet temporaire est alloué sur


Aïe, l'objet temporaire est détruit. Il faut donc que je ruse pour que le
destructeur ne libère pas des ressources que la copie pourrait utiliser.




Merci beaucoup pour ces suggestions,
--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/

Avatar
Cyrille \cns\ Szymanski
Comment créer un tableau d'objets qui ne sont pas des copies d'un
objet de départ.


Tu ne peux pas.


Je veux donc je peux :-)



Mais ce que tu veux ne rempli pas forcément ton réel objectif (ie
faire un code sûr et rapide)


Je veux juste un MyClass[] de taille variable.

En gros vous me proposez de créer un vector<MyClass> et d'ajouter les
objets un par un : les instancier sur la pile puis les copier dans le
tableau. Il faut aussi que dans le destructeur/constructeur je tienne
compte du nombre de références pour ne pas libérer une ressource partagée
par les différentes instances (c'est en fait illusoire car il n'y en a
qu'une et elle est dans le tableau).


Je propose d'allouer de la place pour mes objets (créer un tableau) et de
les instancier un par un en place.


Si quelqu'un me prouve que ma méthode est plus dangereuse et plus lente
alors je l'appellerai Maître.


Cordialement,
--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/




Avatar
Christophe de Vienne
Cyrille "cns" Szymanski wrote:

Mais ne pas copier tes instances n'est pas forcément moins performant
que ce que tu suggères. Dans un fil de discussion récent le sujet est
abordé.


Références ?



<3f42503c$0$6221$

--
Christophe de Vienne
Experience is something you don't get until just after you need it.
Oliver's Law.


Avatar
Christophe de Vienne
Cyrille "cns" Szymanski wrote:


Je propose d'allouer de la place pour mes objets (créer un tableau) et de
les instancier un par un en place.


A partir du moment ou tu veux un tableau de taille dynamique tes objets
seront forcéments copiés, si ce n'est à leur insertion, ne serait-ce qu'au
redimensionnement de ton tableau.

A+

Christophe

--
Christophe de Vienne
Experience is something you don't get until just after you need it.
Oliver's Law.

Avatar
Cyrille \cns\ Szymanski
il semble que tu prennes un malin plaisir à tout embrouiller dans le
post d'après ;)

Peut-être que si tu reformulais ton problème tel qu'il est réellement,
ie en montrant la classe des objets que tu veux gérer dans ton vector,
ce serait un peu plus clair.


Voici donc plusieurs exemples concrets de classes dont je désire créer un
tableau :

struct MyClass {
int nb;
MyClass() {
nb = rand();
cout << "Objet " << nb << "n";
}
~MyClass() {
cout << "Delete " << nb << "n";
}
};

Il faut que les nombres contenus dans les éléments du tableau de MyClass
soient différents (comme le ferait un "MyClass[] vec = new MyClass[]"),
ce que ne fait pas un "vector<MyClass> vec(10)".


Un autre exemple :
struct MyClass {
HANDLE hwnd;
MyClass() {
hwnd = OpenHandle();
}
~MyClass() {
CloseHandle( hwnd );
}
};

Faire
vector<MyClass> vec;
for( i=0; i<10; ++i) {
vec.push_back( MyClass() );
}
ne fonctionne pas car le handle est fermé tout de suite.

Un exemple du même genre qui même s'il n'est pas très orthodoxe a
l'avantage de compiler :

struct MyClass {
char ptr[];
MyClass() {
ptr = new char[10];
sprintf( ptr, "%d", time() );
}
~MyClass() {
delete ptr;
}
};


Merci pour votre temps,
--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/

Avatar
Vivien Gallinaro
Cyrille "cns" Szymanski wrote:

v.push_back( MyClass() ); // l'objet temporaire est alloué sur


Aïe, l'objet temporaire est détruit. Il faut donc que je ruse pour que le
destructeur ne libère pas des ressources que la copie pourrait utiliser.


Mais dans ce cas, tu wrappes (emballe) ta "ressource" dans une classe
rien que pour ça, qui devient membre de MyClass, et dont un rôle
principal est de déterminer si, quand on passe par son destructeur, la
ressource doit être libérée.

Ca sent le pointeur quelque part (dans la nouvelle classe, je dirais),
et on me dit que ce que je raconte navigue entre les idées de pointeur
intelligent, comptage de références et singleton. Seulement, je ne vois
pas pourquoi tu t'acharnes sur cette histoire de temporaire : c'est pas
parce qu'on passe dans un destructeur qu'on doit forcément jeter tout ce
qu'il y avait dans l'instance...

En plus, jouer avec les vectors, malloc et des placement new... bien sûr
je suis loin d'être un spécialiste, mais je pense que c'est louche.
Tu dis que ton tableau doit être de taille "vraiment" dynamique, donc je
suppose qu'à un moment tu vas faire quelque chose vec.reserve() ou
vec.push_back() (si c'est un vector) ou un bon vieux realloc() qui sent
le fromage... dans une opération de ce genre, il va bien falloir
déplacer les éléments qui sont déjà dedans ? A part memcpy() et le
passage par des constructeurs de copie, je ne vois pas beaucoup d'autre
solution (1). La première, c'est pas "C++ fashion", et la deuxième
laisse supposer que l'ancien tableau va (un jour) être libéré. Si ce
n'est pas par free() (et j'imagine que faire free() sur un truc qui est
passé par new laisse un état indéfini), ce sera par le destructeur des
éléments de l'ancien tableau... et là, sans vouloir faire de mauvais
esprit, comme tu disais :

Aïe, l'objet temporaire est détruit. Il faut donc que je ruse pour
que le destructeur ne libère pas des ressources que la copie
pourrait utiliser.


C'est très brouillon comme réflexion, mais je crois pas que tu puisses
t'en tirer aussi indéfiniment que tu le souhaites avec les solutions que
tu envisages.

Gourgouilloult du Clapotis
En espérant ne pas en rajouter que du bruit... ;-/

(1) Sans trop y réfléchir, il est vrai.


Avatar
Cyrille \cns\ Szymanski
A partir du moment ou tu veux un tableau de taille dynamique tes
objets seront forcéments copiés, si ce n'est à leur insertion, ne
serait-ce qu'au redimensionnement de ton tableau.


Alors ma question est comment déplacer un objet ?

--
_|_|_| CnS
_|_| for(n=0;b;n++)
_| b&=b-1; /*pp.47 K&R*/

1 2 3 4