c++ strict aliasing problem --- driving me crazy
Okay... I'm getting kind of desperate trying to get this code to work with strict aliasing turned on (and -O3).
I was unable to shorten the code down (sry...) so it's fairly long ~170 lines...struct S
{
enum
{
leaf,
node
} type; // the type of the structure. leaf means has a value. node has vector.
union
{
int value;
std::vector<struct S*> *v;
} data; // the data. only one is active dependant on the type
};
//compares two structs
bool cmpStructs( const struct S *s1, const struct S *s2 );
//compares the 'top levels' i.e. type and if leaves then also the value
bool cmpStructs1( const struct S *s1, const struct S *s2 );
int main( void )
{
// Create the structure: s1 = [1,2] s2 = [1,3]. Just some random stuff
struct S *s1 = new struct S;
struct S *s2 = new struct S;
s1->type = s2->type = S::node;
s1->data.v = new std::vector<struct S*>( 2U );
s2->data.v = new std::vector<struct S*>( 2U );
struct S *t = new struct S;
t->type = S::leaf;
t->data.value = 1;
s1->data.v->front() = t;
t = new struct S;
t->type = S::leaf;
t->data.value = 2;
s1->data.v->back() = t;
t = new struct S;
t->type = S::leaf;
t->data.value = 1;
s2->data.v->front() = t;
t = new struct S;
t->type = S::leaf;
t->data.value = 3;
s2->data.v->back() = t;
//compare s1 and s2. Note: the result is actually not important. the problem is the crash.
if( cmpStructs( s1, s2 ) )
std::cout << "equal" << std::endl;
else
std::cout << "not equal" << std::endl;
return 0;
}
bool cmpStructs( const struct S *s1, const struct S *s2 )
{
// compare 'top-level'
if( cmpStructs1( s1, s2 ) == false )
return false;
// i.e. s1->type == s2->type and s1->value == s2->value
if( s1->type != S::node )
return true;
// different vector sizes don't compare the same
if( s1->data.v->size() != s2->data.v->size() )
return false;
// used to iterate over all elements in the tree structure of struct S
struct const_iteratorList
{
std::vector<struct S*>::const_iterator it, end;
struct const_iteratorList *next, *previous;
} l1, l2, *c1, *c2;
c1 = &l1;
c2 = &l2;
bool equal = true;
c1->it = s1->data.v->begin();
c1->end = s1->data.v->end();
c2->it = s2->data.v->begin();
c2->end = s2->data.v->end();
c1->previous = c2->previous = c1->next = c2->next = NULL;
do
{
while( c1->it != c1->end )
{// This is where it crashes. Though basically the same stuff as above
if( cmpStructs1( *(c1->it), *(c2->it) ) == false )
{
equal = false;
break;
}
if( (*(c1->it))->type != S::node )
{
++(c1->it);
++(c2->it);
continue;
}
if( (*(c1->it))->data.v->size() != (*(c2->it))->data.v->size() )
{
equal = false;
break;
}
// since *(c1->it) is not a leaf we need to look into its subnodes
c1->next = new struct const_iteratorList;
c2->next = new struct const_iteratorList;
c1->next->it = (*(c1->it))->data.v->begin();
c1->next->end = (*(c1->it))->data.v->end();
c2->next->it = (*(c2->it))->data.v->begin();
c2->next->end = (*(c2->it))->data.v->en开发者_JAVA技巧d();
c1->next->previous = c1;
c2->next->previous = c2;
c1 = c1->next;
c2 = c2->next;
c1->next = c2->next = NULL;
}
if( c1->previous != NULL )
{
c1 = c1->previous;
c2 = c2->previous;
delete c1->next;
delete c2->next;
++(c1->it);
++(c2->it);
} else
break;
} while( equal == true );
while( c1->previous != NULL )
{
c1 = c1->previous;
c2 = c2->previous;
delete c1->next;
delete c2->next;
}
return equal;
}
bool cmpStructs1( const struct S *s1, const struct S *s2 )
{
if( s1->type == S::node )
{
if( s2->type == S::node )
return true;
} else
{
if( s2->type == S::node )
return false;
if( s1->data.value == s2->data.value )
return true;
}
return false;
}
The problem is easily described: It works without -fstrict-aliasing and breaks with it.
with 'breaks' I mean 'crashes'. Please help me get it to work in both cases :P Thanks!!! in advance (I've tried for some hours...)EDIT:
It crashes. Basically I have no idea of what could be wrong so I have tried to narrow things down by taking away code paths and retrying... But it didn't take me anywhere.EDIT: added some comments
Here's a question: why would you place an int
and a vector<int>*
in a union? That makes both members of the union share the same memory (i.e. updating value
overwrites v
and vice versa).
It looks to me like you'd rather be using a struct:
struct
{
int value;
std::vector<struct S*> *v;
} data;
This lays the objects sequentially in memory (i.e. v
is now after value
, as opposed to "on top of" value
).
Also, in this case, you may wish to just use a normal vector, as you don't have the restriction on unions anymore:
struct
{
int value;
std::vector<struct S*> v;
}
But that's up to you.
Edit
As per Billy's comment, you can also keep things simpler and make the struct nice and flat:
struct S
{
enum
{
leaf,
node
} type;
int value;
vector<S*> *v
};
This seems to have been a bug. It works with GCC 4.6.1. Just want to close the question...
精彩评论