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

probleme avec le constructeur par copie :-(

13 réponses
Avatar
PasDeSpam
vos discutions sont tres "pointues" pour moi.

l'utilisation d'une classe construite par copie (ou par affectation)
pose des problemes dans mon code.

voici la classe :

class RXBBPatterns {


RXBitBoard board;
RXPattern* pattern;

public :


RXBBPatterns();

//constructeur par copie
RXBBPatterns(const RXBBPatterns& src);

RXBBPatterns& operator=(const RXBBPatterns& src);

~RXBBPatterns();


bool (RXBBPatterns::*generate_patterns[64][2])(RXMove& move) const;
void init_generate_patterns();


};


RXBBPatterns::RXBBPatterns(): pattern(new RXPattern()) {

init_generate_patterns();

pattern->set_WHITE_D4();
pattern->set_BLACK_E4();
pattern->set_BLACK_D5();
pattern->set_WHITE_E5();

}

RXBBPatterns::RXBBPatterns(const RXBBPatterns& src) : board(src.board),
pattern(new RXPattern()) {


memcpy(pattern, src.pattern, sizeof(RXPattern));

init_generate_patterns();

}

RXBBPatterns::~RXBBPatterns() {
delete pattern;
}


RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src) {

if(this != &src) {

board = src.board;

memcpy(pattern, src.pattern, sizeof(RXPattern));

}

return *this;
}

est ce que les constructeurs et l'operator= sont correctement ecrits?

quand j'utilise le debugeur j'ai ce message:

Roxane(1266,0xb0103000) malloc: *** error for object 0x358680: incorrect
checksum for freed object - object was probably modified after being
freed.
*** set a breakpoint in malloc_error_break to debug


merci

10 réponses

1 2
Avatar
Fabien LE LEZ
On Wed, 17 Sep 2008 18:03:51 +0200, (Bruno Causse):

RXBitBoard board;
RXPattern* pattern;



Étant donnés tes constructeur et opérateur de copie, je ne comprends
pas pourquoi tu utilises un pointeur pour pattern.
Il me semble que
RXPattern pattern;
serait bien plus adapté.
Avatar
PasDeSpam
Fabien LE LEZ wrote:

On Wed, 17 Sep 2008 18:03:51 +0200, (Bruno Causse):

>RXBitBoard board;
>RXPattern* pattern;

Étant donnés tes constructeur et opérateur de copie, je ne comprends
pas pourquoi tu utilises un pointeur pour pattern.
Il me semble que
RXPattern pattern;
serait bien plus adapté.




j'utilise peut etre a tort une "ruse de sioux"

j'ai une deuxieme classe

class RXMove {

friend class RXBitBoard;
friend class RXBBPatterns;
friend class RXEngine;
friend class RXEvaluation;

char position;
unsigned long long square;
unsigned long long flipped;
int n;
unsigned long long hash_code;
int score;
RXMove* next;

RXPattern* pattern;
RXPattern* undo_pattern;

public :


RXMove() : position(NOMOVE), square(0ULL), flipped(0ULL), n(0),
hash_code(0ULL), score(0), next(NULL), pattern(NULL), undo_pattern(NULL)
{
pattern = new RXPattern();
};

RXMove(const RXMove& src) {
//std::cout << "constructeur de copie RXMove" << std::endl;
pattern = new RXPattern();

memcpy(pattern, src.pattern, sizeof(RXPattern));

};

RXMove& operator=(const RXMove& src) {
std::cout << "affectation par copie de RXMove" << std::endl;
if(this != &src) {
memcpy(pattern, src.pattern, sizeof(RXPattern));
}
return *this;
};


~RXMove() {
/ /std::cout << "destructeur RXMove" << std::endl;
d elete pattern;
};


static std::string index_to_coord(int index);
static int coord_to_index(std::string coord);

void sort_bestmove(const int bestmove);
void sort_by_score();

//debug
friend std::ostream& operator<<(std::ostream& os, RXMove* list);

};


et j'echange entre les RXBBPattern et RXmove les patterns

du genre

inline void RXBBPatterns::do_move(const RXMove& move) {
board.do_move(move);
pattern = move.pattern;
}

inline void RXBBPatterns::undo_move(const RXMove& move) {
pattern = move.undo_pattern;
board.undo_move(move);
}
Avatar
James Kanze
On Sep 17, 6:03 pm, (Bruno Causse) wrote:
vos discutions sont tres "pointues" pour moi.



l'utilisation d'une classe construite par copie (ou par
affectation) pose des problemes dans mon code.



voici la classe :



class RXBBPatterns {



RXBitBoard board;
RXPattern* pattern;



public :



RXBBPatterns();



//constructeur par copie
RXBBPatterns(const RXBBPatterns& src);



RXBBPatterns& operator=(const RXBBPatterns& src);



~RXBBPatterns();



bool (RXBBPatterns::*generate_patterns[64][2])(RXMove& move) const;



Je suppose qu'il y a plus, parce que sinon, je ne vois pas à
quoi vont pointer ces pointeurs. C'est de toute façon un idiome
assez original.

void init_generate_patterns();
};



RXBBPatterns::RXBBPatterns(): pattern(new RXPattern()) {



init_generate_patterns();



pattern->set_WHITE_D4();
pattern->set_BLACK_E4();
pattern->set_BLACK_D5();
pattern->set_WHITE_E5();
}



RXBBPatterns::RXBBPatterns(const RXBBPatterns& src) : board(src.board),
pattern(new RXPattern()) {



memcpy(pattern, src.pattern, sizeof(RXPattern));



Ici, il faudrait savoir plus sur RXPattern. En général, memcpy
ne marche que sur les POD.

init_generate_patterns();
}



RXBBPatterns::~RXBBPatterns() {
delete pattern;
}



RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src) {



if(this != &src) {



À quoi sert ce test ? (Typiquement, s'il le faut, c'est qu'il y
a un problème ailleurs. Mais dans ce cas-ci, je ne vois pas
pourquoi il le faudrait.)

board = src.board;
memcpy(pattern, src.pattern, sizeof(RXPattern));
}



return *this;
}



est ce que les constructeurs et l'operator= sont correctement ecrits?



C'est difficile à dire sans en voir plus. Mais le test pour
l'affectation à soi et les memcpy me semble suspects.

quand j'utilise le debugeur j'ai ce message:



Roxane(1266,0xb0103000) malloc: *** error for object 0x358680: incorrect
checksum for freed object - object was probably modified after being
freed.
*** set a breakpoint in malloc_error_break to debug



Sans le dump de la pile, qui sais. D'où a été appelé malloc ?

--
James Kanze (GABI Software) email:
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
Michel Decima
Fabien LE LEZ wrote:
On Wed, 17 Sep 2008 18:03:51 +0200, (Bruno Causse):

RXBitBoard board;
RXPattern* pattern;



Étant donnés tes constructeur et opérateur de copie, je ne comprends
pas pourquoi tu utilises un pointeur pour pattern.
Il me semble que
RXPattern pattern;
serait bien plus adapté.




Moi c'est surtout le memcpy qui me derange dans la copie de pattern.
Ca ne serait pas plus simple d'utiliser le constructeur copie ou
l'operateur d'affectation de la classe pattern ?

Quelque-chose dans le genre:

XBBPatterns::RXBBPatterns(const RXBBPatterns& src)
: board( src.board )
, pattern( new RXPattern( *src.pattern ) )
{}

RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src)
{
if ( this != &src ) {
board = src.board ;
pattern = src.pattern ;
}
return *this ;
}
Avatar
James Kanze
On Sep 17, 9:54 pm, Michel Decima wrote:
Fabien LE LEZ wrote:



RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src)
{
if ( this != &src ) {
board = src.board ;
pattern = src.pattern ;



Tant que pattern reste un pointeur, il faudrait:
*pattern = *src.pattern ;
Et s'il cesse d'être un pointeur, la version implicite du
compilateur fait l'affaire.

}
return *this ;
}



On finit donc avec:

RXBBPatterns&
RXBBPatterns::operator=(
RXBBPatterns const& other )
{
board = src.board ;
*pattern = *src.pattern ;
return *this ;
}

--
James Kanze (GABI Software) email:
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
Michel Decima
James Kanze a écrit :
On Sep 17, 9:54 pm, Michel Decima wrote:
Fabien LE LEZ wrote:



RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src)
{
if ( this != &src ) {
board = src.board ;
pattern = src.pattern ;



Tant que pattern reste un pointeur, il faudrait:
*pattern = *src.pattern ;
Et s'il cesse d'être un pointeur, la version implicite du
compilateur fait l'affaire.



Oups... tu as raison, il faut dereferencer le pointeur.
C'etait bien ce que je voulais faire, mais j'ai oublie
les '*' dans la recopie du code.
Avatar
Bruno Causse
"James Kanze" a écrit dans le message de news:

On Sep 17, 6:03 pm, (Bruno Causse) wrote:


bool (RXBBPatterns::*generate_patterns[64][2])(RXMove& move) const;





Je suppose qu'il y a plus, parce que sinon, je ne vois pas à
quoi vont pointer ces pointeurs. C'est de toute façon un idiome
assez original.



memcpy(pattern, src.pattern, sizeof(RXPattern));





Ici, il faudrait savoir plus sur RXPattern. En général, memcpy
ne marche que sur les POD.



class RXPattern {

public:

//data 128 bytes (align)


short diag_5a;

short diag_5b;

short diag_5c;

short diag_5d;

short diag_6a;

short diag_6b;

short diag_6c;

short diag_6d;

short diag_7a;

short diag_7b;

short diag_7c;

short diag_7d;

short diag_8a;

short diag_8b;

short reverved_a;

short reverved_b;

short hv_4a;

short hv_4b;

short hv_4c;

short hv_4d;

short hv_3a;

short hv_3b;

short hv_3c;

short hv_3d;

short hv_2a;

short hv_2b;

short hv_2c;

short hv_2d;

short corner2x5a;

short corner2x5b;

short corner2x5c;

short corner2x5d;

short corner2x5e;

short corner2x5f;

short corner2x5g;

short corner2x5h;

short edge64a;

short edge64b;

short edge64c;

short edge64d;

int corner11a;

int corner11b;

int corner11c;

int corner11d;

int edge2XCa;

int edge2XCb;

int edge2XCc;

int edge2XCd;

int reverved_1;

int reverved_2;

int reverved_3;

int reverved_4;


.../...
}

RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src) {





if(this != &src) {





À quoi sert ce test ? (Typiquement, s'il le faut, c'est qu'il y
a un problème ailleurs. Mais dans ce cas-ci, je ne vois pas
pourquoi il le faudrait.)



je pensais que c'etait la facon "classique" d'ecrire les operators

je precise, mon prog fonctionne depuis plusieurs années sans probleme.

aujourd'hui je tente de parralelliser quelque taches, donc j'ai besion de
faire des copies d'objet RXBBPattern.
et la plantage.

si j'utilise le code multiThread avec un seul thread et au lieu de passer
une copie je passe l'objet lui meme je n'ai aucun probleme
Avatar
Bruno Causse
"Bruno Causse" a écrit dans le message de news:
1infayy.1w7pbjw1wsq0ocN%
vos discutions sont tres "pointues" pour moi.



comme souvent (toujours chez moi) le bug etait entre l'ecran et la chaise.

c'etait un bug de conception :(

les RXMoves etaient construits avec l'original, et utilisés avec la copie.
Donc le pointeur de "rappel" undo_move pointait
sur le RXBBPattern original et non sa copie d'ou le bug a la liberation.

merci
Avatar
James Kanze
On Sep 18, 11:18 am, "Bruno Causse" wrote:
"James Kanze" a écrit dans le message de news:

On Sep 17, 6:03 pm, (Bruno Causse) wrote:



[...]
>> RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src) {
>> if(this != &src) {
>À quoi sert ce test ? (Typiquement, s'il le faut, c'est qu'il y
>a un problème ailleurs. Mais dans ce cas-ci, je ne vois pas
>pourquoi il le faudrait.)



je pensais que c'etait la facon "classique" d'ecrire les
operators =



C'était conseillé souvent avant l'introduction des exceptions,
mais pour des raisons précises qui ne s'appliquent pas ici.

Imagine un instant que ton pointeur designait quelque chose dont
la taille était variable. Et que dans l'opérateur d'affectation,
tu voulais faire un delete de l'ancien objet, et une nouvelle
allocation. Si tu écrivais :
delete pointer ;
pointer = new Object( *other.pointer ) ;
, il y avait un problème si other était en fait une réfèrence au
même objet. Une solution souvent proposée alors était le test
pour l'auto-affectation. (Mais s'il ne pose jamais de problème
en soi, il n'est nécessaire que dans ce cas-ci. Donc, pas dans
ton cas, où il n'y a pas de delete.)

Avec l'introduction des exceptions, on s'est aperçu que cette
solution ne marchait pas ; le new peut lever une exception, qui
laisse l'objet dans un drôle d'état, et en suite, quand on en
appel le destructeur... pointer contient toujours la valeur dont
on a fait le delete. La règle incontournable est devenue
d'exécuter tout ce qui pourrait lever une exception avant de
modifier quoique ce soit dans l'objet, avec l'idiome de swap le
moyen plus ou moins préféré pour y arriver. Dans le cas
problèmatique que je viens de présenter, donc, on écrirait :
Object* tmp = new Object( *other.pointer ) ;
delete pointer ;
pointer = tmp ;
ou, avec l'idiome de swap, quelque chose du genre :
MyClass tmp( *other ) ;
std::swap( pointer, tmp.pointer ) ;
// et ainsi de suite sur les autres éléments...
C'est ensuite le destructeur de tmp qui s'occupera de faire les
delete sur les anciennes valeurs. (Note bien que l'idiome du
swap ne fonctionne que si tous les membres supporte un swap
nothrow.)

Ensuite, j'ai remarqué que dans les cas où il *fallait* le test
pour l'auto-affectation (comme dans mon exemple), on n'était
probablement pas exception-safe.

je precise, mon prog fonctionne depuis plusieurs années sans
probleme.



Certes. Dans ton cas, le test n'est pas nécessaire. Et même,
selon l'utilisation de l'objet, c'est bien possible que tu n'as
jamais eu une affectation d'un objet à lui-même. Tu es en fait
en train d'appliquer un idiome que tu as vu quelque part sans
réelement savoir pourquoi, ni même si ton code en est concerné.

--
James Kanze (GABI Software) email:
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
Chanclou
James Kanze a écrit :
On Sep 18, 11:18 am, "Bruno Causse" wrote:
"James Kanze" a écrit dans le message de news:

On Sep 17, 6:03 pm, (Bruno Causse) wrote:



[...]
RXBBPatterns& RXBBPatterns::operator=(const RXBBPatterns& src) {
if(this != &src) {


À quoi sert ce test ? (Typiquement, s'il le faut, c'est qu'il y
a un problème ailleurs. Mais dans ce cas-ci, je ne vois pas
pourquoi il le faudrait.)





je pensais que c'etait la facon "classique" d'ecrire les
operators >


C'était conseillé souvent avant l'introduction des exceptions,
mais pour des raisons précises qui ne s'appliquent pas ici.

Imagine un instant que ton pointeur designait quelque chose dont
la taille était variable. Et que dans l'opérateur d'affectation,
tu voulais faire un delete de l'ancien objet, et une nouvelle
allocation. Si tu écrivais :
delete pointer ;
pointer = new Object( *other.pointer ) ;
, il y avait un problème si other était en fait une réfèrence au
même objet. Une solution souvent proposée alors était le test
pour l'auto-affectation. (Mais s'il ne pose jamais de problème
en soi, il n'est nécessaire que dans ce cas-ci. Donc, pas dans
ton cas, où il n'y a pas de delete.)

Avec l'introduction des exceptions, on s'est aperçu que cette
solution ne marchait pas ; le new peut lever une exception, qui
laisse l'objet dans un drôle d'état, et en suite, quand on en
appel le destructeur... pointer contient toujours la valeur dont
on a fait le delete. La règle incontournable est devenue
d'exécuter tout ce qui pourrait lever une exception avant de
modifier quoique ce soit dans l'objet, avec l'idiome de swap le
moyen plus ou moins préféré pour y arriver. Dans le cas
problèmatique que je viens de présenter, donc, on écrirait :
Object* tmp = new Object( *other.pointer ) ;
delete pointer ;
pointer = tmp ;
ou, avec l'idiome de swap, quelque chose du genre :
MyClass tmp( *other ) ;
std::swap( pointer, tmp.pointer ) ;
// et ainsi de suite sur les autres éléments...
C'est ensuite le destructeur de tmp qui s'occupera de faire les
delete sur les anciennes valeurs. (Note bien que l'idiome du
swap ne fonctionne que si tous les membres supporte un swap
nothrow.)

Ensuite, j'ai remarqué que dans les cas où il *fallait* le test
pour l'auto-affectation (comme dans mon exemple), on n'était
probablement pas exception-safe.

je precise, mon prog fonctionne depuis plusieurs années sans
probleme.



Certes. Dans ton cas, le test n'est pas nécessaire. Et même,
selon l'utilisation de l'objet, c'est bien possible que tu n'as
jamais eu une affectation d'un objet à lui-même. Tu es en fait
en train d'appliquer un idiome que tu as vu quelque part sans
réelement savoir pourquoi, ni même si ton code en est concerné.



Je vois un autre intérêt à ce test d'évitement d'auto- affectation,
lorsque l'objet est constitué de nombreuses variables membres, cela
évite une recopie qui prend du temps. Bien que sachant qu'une
affectation est toujours moins coûteuse qu'un test, ce n'est valable
que pour les gros objets.
--
James Kanze (GABI Software) email:
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


1 2