Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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
Gabriel Dos Reis
"Cyrille "cns" Szymanski" writes:

| 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 ?

je n'arrive pas à donner un sens à cette question, même (et surtout)
avec le code que tu donnes.

Aussi, new T() est à utiliser avec Paolo Parcimoni et Youri Abonessian.

-- Gaby
Avatar
Loïc Joly
Cyrille "cns" Szymanski wrote:
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 ?


J'ai du mal à comprendre...


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()) );
}


Ca code m'a l'air équivalent à (mais je vois pas trop le rapport avec la
question qu'il y a avant...) :

vector<MyClass> vec (10);
vec.reserve(20);


--
Loïc

Avatar
Fabien SK
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 );


Sans répondre à la question:

new -> delete (et pas free)

Avatar
Christophe Lephay
"Cyrille "cns" Szymanski" a écrit dans le message de
news:
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 ?



Celà n'a pas grand chose à voir avec resize, mais tes objets *doivent*
pouvoir être copiables pour pouvoir être utilisés avec std::vector.

Partant de là, que les objets stockés dans ton vector aient été créés via un
constructeur normal ou un constructeur de copie importe peu.

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 :



Il n'y a pas de gâchis de mémoire. Quand tu fais un push_back, le fait qu'il
se passe une copie de l'objet fourni n'a pas d'impact sur la mémoire, les
objets initiaux étant soient des temporaires créés à la volée et supprimés à
la fin de l'instruction (sur la pile), ou des objets auto supprimés à la fin
du bloc ou de la fonction dans lequel ils ont été déclarés :

void fonction()
{
std::vector< objet > v; // (1)

v.push_back( objet() ); // (2)

objet o; // (3)
v.push_back( o ); // (4)
}

(1) le vector v étant déclaré dans la fonction, il sera supprimé ainsi que
tous les objets qu'il contient à la fin de la fonction.
(2) un objet est créé à la volée et est supprimé à la fin de l'instruction,
une copie reste dans le vector.
(3) l'objet o est supprimé à la fin de la fonction
(4) la copie de l'objet o est supprimée en même temps que tous les autres
objets que contient le vector à la fin de la fonction. Si v n'était pas
local à la fonction, la copie subsisterait alors que l'objet initial o
aurait été supprimé.

Le fait d'offrir une sémantique de valeur permet au compilateur de savoir
quand les objets doivent être créés et détruits. Il n'y a pas de gachis de
mémoire sauf si les objets que tu stockes dans ton vector sont des objets
globaux, ce qui est de toute façon une très mauvaise idée dans la quasi
totalité des cas.

Chris

Avatar
Cyrille \cns\ Szymanski
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 );


Sans répondre à la question:

new -> delete (et pas free)



Oui, j'ai délibérément utilisé free ici pour que le destructeur ne soit pas
appelé.

Supposons que l'appel au constructeur de MyClass récupère un objet système
(un HANDLE, MUTEX etc. par exemple) pour son usage. Cet objet est libéré
dans le destructeur.

En faisant "delete tmp", le destructeur de ma classe est appelé sur
l'instance temporaire et le HANDLE est libéré. Dans ce cas, l'instance de
la classe contenue dans le tableau ne peut plus fonctionner correctement.

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


Avatar
Cyrille \cns\ Szymanski
void fonction()
{
std::vector< objet > v; // (1)

v.push_back( objet() ); // (2)

objet o; // (3)
v.push_back( o ); // (4)
}


(5)



(1) le vector v étant déclaré dans la fonction, il sera supprimé ainsi
que tous les objets qu'il contient à la fin de la fonction.
(2) un objet est créé à la volée et est supprimé à la fin de
l'instruction, une copie reste dans le vector.
(3) l'objet o est supprimé à la fin de la fonction
(4) la copie de l'objet o est supprimée en même temps que tous les
autres objets que contient le vector à la fin de la fonction. Si v
n'était pas local à la fonction, la copie subsisterait alors que
l'objet initial o aurait été supprimé.


C'est très clair pour moi et je n'avais aucun doute là dessus.

Mon problème est le suivant :

(3) "objet" est instancié en o, disons qu'il réclame un HANDLE (MUTEX...
ou tout autre objet du genre) au système d'exploitation.
(4) une copie de o est placée dans le vector
(5) o est détruit, le HANDLE est libéré
(après 5) l'instance d'objet dans le vector ne fonctionne plus car son
HANDLE a été libéré.


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

Avatar
Fabien LE LEZ
On 22 Aug 2003 13:05:53 GMT, "Cyrille "cns" Szymanski"
wrote:

Oui, j'ai délibérément utilisé free ici pour que le destructeur ne soit pas
appelé.


Mais si je ne m'abuse, rien n'impose que free() libère correctement de
la mémoire allouée par new.

Avatar
Cyrille \cns\ Szymanski
je n'arrive pas à donner un sens à cette question, même (et surtout)
avec le code que tu donnes.


Ok, reformulation alors :

Comment créer un tableau d'objets qui ne sont pas des copies d'un objet
de départ.

Le code suivant ne réalise pas ce que je veux car MyClass n'est
instanciée qu'une seule fois puis copiée 10 fois dans le tableau, alors
que je voudrais que MyClass soit instanciée 10 fois et que chaque
instance soit un élément du tableau.

#include <iostream>
#include <vector>

using namespace std;

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

int main() {
vector<MyClass> vec(10);
}


J'ai deux versions de code qui réalisent presque ce que je veux :

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

Le code précédent est incorrect car new instancie 10 MyClass dont la
mémoire n'est pas libérée ensuite (ces objets ne sont plus nécessaires
car une copie a été placée dans le tableau).

#include <new>

int main() {
MyClass *vec = (MyClass*)malloc( sizeof(MyClass) * 10 );
for( int i=0; i<10; ++i ) {
new (vec[i]) MyClass;
}
}

Le code précédent n'est pas beau car il appelle malloc() et joue avec les
pointeurs mais il fait exactement ce que je veux.


Note: Je ne peux pas utiliser "MyClass[] vec = new MyClass[10]" car je ne
pourrai plus modifier la taille du tableau.


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

Avatar
Cyrille \cns\ Szymanski
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[].

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

Avatar
Christophe Lephay
"Cyrille "cns" Szymanski" a écrit dans le message de
news:
(3) "objet" est instancié en o, disons qu'il réclame un HANDLE (MUTEX...
ou tout autre objet du genre) au système d'exploitation.
(4) une copie de o est placée dans le vector
(5) o est détruit, le HANDLE est libéré
(après 5) l'instance d'objet dans le vector ne fonctionne plus car son
HANDLE a été libéré.


Si toutes les instances partagent des ressources identiques, une solution
qui convient est de les gérer à l'aide d'un comptage de référence dans les
constructeurs/destructeurs (dans certains cas, l'OS est à même de le faire
lui même)...

Chris

1 2 3 4