c ++ проблема строгого алиасинга --- сводит меня с ума - PullRequest
1 голос
/ 06 сентября 2011

Хорошо ... Я отчаянно пытаюсь заставить этот код работать при включенном строгом алиасинге (и -O3).
Мне не удалось сократить код (sry ...), поэтому он довольно длинный ~ 170 строк ...

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

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

Проблема легко описывается: она работает без -fstrict-aliasing и ломается с ней.
с «перерывами» я имею в виду «вылетает». Пожалуйста, помогите мне заставить его работать в обоих случаях: P
Спасибо!!! заранее (я пробовал несколько часов ...)

EDIT:
Вылетает.
По сути, я понятия не имею, что может быть не так, поэтому я попытался сузить круг, убрав пути кода и повторив попытку ... Но это никуда меня не привело.

РЕДАКТИРОВАТЬ: добавил некоторые комментарии

Ответы [ 2 ]

0 голосов
/ 01 ноября 2011

Кажется, это ошибка. Работает с GCC 4.6.1. Просто хочу закрыть вопрос ...

0 голосов
/ 06 сентября 2011

Вот вопрос: зачем вы помещаете int и vector<int>* в союз?Это позволяет обоим членам объединения использовать одну и ту же память (т. Е. Обновление value перезаписывает v и наоборот).

Мне кажется, что вы предпочитаете использовать структуру:

struct
{
    int value;
    std::vector<struct S*> *v;
} data;

Это кладет объекты последовательно в память (то есть v теперь после value, в отличие от "поверх" value).

Такжев этом случае вы можете использовать обычный вектор, поскольку у вас больше нет ограничений на союзы:

struct
{
    int value;
    std::vector<struct S*> v;
}

Но это ваше дело.

Редактировать

Согласно комментарию Билли, вы также можете упростить задачу и сделать структуру красивой и плоской:

struct S
{
    enum
    {
        leaf,
        node
    } type;

    int value;
    vector<S*> *v
};
...