Использование memcpy в конструкторе
От: alex2077  
Дата: 14.02.08 11:46
Оценка:
используя библиотеку gSOAP натолкнулся на грабли с генеренными ее средствами файлами, проблему можно свети к такому примеру:

struct my_str
{
    my_str() {}
    virtual ~my_str() {}
    
    char buf[100000];
};

void copy(my_str* to, const my_str* from)
{
    memcpy(to, from, sizeof(my_str));
}

class my_class : public my_str
{
public:
    my_class() {}

    my_class(const my_str& from)
    {
        //этот вызов корень всех бед 
        copy(this, &from);
    }        
   
    // вызов из функции другой виртуальной функции 
    // по сути вызов виртуальной функции изнутри класса
    virtual int f()
    {
        return x(rand());
    }
    
    virtual int x(int j)
    {
        return j*2;
    }
};

int main(int argc, char *argv[])
{
    my_class m1;
    
    //убедимся что все работает
    m1.f();
    
    my_str str;
    my_class m2(str);
   
    //вызов x из вне - все работает
    m2.x();

    // А вот тут core dump получаем на вызове my_class::x
    m2.f();
    
    return 0;
}



есть идеи как это объяснить?
P.S. если вызов copy перенести в конструктор копирывания my_str, то все работает замечательно!!!
Re: Использование memcpy в конструкторе
От: alex2077  
Дата: 14.02.08 11:49
Оценка:
Да, забыл указать, что все происходит под gcc version 3.4.6 20060404 (Red Hat 3.4.6-3) под другими не пробовал.
Re: Использование memcpy в конструкторе
От: Ovl Россия  
Дата: 14.02.08 11:55
Оценка:
Здравствуйте, alex2077, Вы писали:

A>есть идеи как это объяснить?



у производного класса добавилось два виртуальных метода, поэтому sizeof(my_str) != sizeof(my_class), и это в любом случае не podo типы
поэтому копирование через copy(...), где кстати происходит приведение this к базовому классу, не будет корректным
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re: Использование memcpy в конструкторе
От: Erop Россия  
Дата: 14.02.08 11:58
Оценка:
Здравствуйте, alex2077, Вы писали:

A>есть идеи как это объяснить?

A>P.S. если вызов copy перенести в конструктор копирывания my_str, то все работает замечательно!!!

А что тут объяснять?
Полиморфные классы с наследованием -- это далеко не POD, так что по memcpy он копироваться и не должен.

Если конкретнее проблему разобрать, то во время работы конструктора базы указатель на таблицу виртуальных функции соответсвует базе, а при работе конструктора наследника -- наследника.

Соответсвенно компилятор генерит там код, который указатели переписывает. И если ты по ходу пьесы туда влезешь с memcpy, то может быть всё что угодно...

А когда ты конструируешь копию, то все указатели уже совпадабют и в этой реализации тебе везёт и ничего плохого не происходит...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Использование memcpy в конструкторе
От: LaptevVV Россия  
Дата: 14.02.08 12:02
Оценка:
Здравствуйте, alex2077, Вы писали:

A>используя библиотеку gSOAP натолкнулся на грабли с генеренными ее средствами файлами, проблему можно свети к такому примеру:


A>
A>struct my_str
A>{
A>    my_str() {}
A>    virtual ~my_str() {}
    
A>    char buf[100000];
A>};

A>void copy(my_str* to, const my_str* from)
A>{
A>    memcpy(to, from, sizeof(my_str));
A>}

A>class my_class : public my_str
A>{
A>public:
A>    my_class() {}

A>    my_class(const my_str& from)
A>    {
A>        //этот вызов корень всех бед 
A>        copy(this, &from);
A>    }        
A>    
A>

А напиши-ка ты memcpy непосредственно в конструкторе, причем не в this, а непосредственно в массив.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Использование memcpy в конструкторе
От: Кодт Россия  
Дата: 14.02.08 12:09
Оценка: 2 (1) +1
Здравствуйте, alex2077, Вы писали:

A>
A>struct my_str
A>{
A>    my_str() {}
A>    virtual ~my_str() {}
    
A>    char buf[100000];
A>};

A>void copy(my_str* to, const my_str* from)
A>{
A>    memcpy(to, from, sizeof(my_str));
A>}
// поубивать надо за такое.
// правильно написать так
void copy(my_str* to, const my_str* from)
{
    *to = *from; // оператор присваивания неявно определён компилятором
}

A>class my_class : public my_str
A>{
A>public:
A>    my_class() {}

A>    my_class(const my_str& from)
// неявно вызван my_str::my_str()
// в этом месте vfptr указывает на vtbl my_str
A>    {
// а в этом месте он уже указывает на vtbl my_class
A>        //этот вызов корень всех бед 
A>        copy(this, &from);
// после сырого копирования он снова указывает на my_str
A>    }
   
A>    // вызов из функции другой виртуальной функции 
A>    // по сути вызов виртуальной функции изнутри класса
A>    virtual int f()
A>    {
A>        return x(rand());
A>    }
    
A>    virtual int x(int j)
A>    {
A>        return j*2;
A>    }
A>};

A>int main(int argc, char *argv[])
A>{
A>    my_class m1;
    
A>    //убедимся что все работает
A>    m1.f();
    
A>    my_str str;
A>    my_class m2(str);
   
A>    //вызов x из вне - все работает
A>    m2.x();
// компилятор знает, что фактический тип m2 - это my_class,
// и заменил виртуальный вызов статическим

A>    // А вот тут core dump получаем на вызове my_class::x
A>    m2.f();
// точно так же, статический вызов my_class::f()
// в методе my_class::f() фактический тип объекта не известен на стадии компиляции
// поэтому там делается виртуальный вызов
// а vfptr указывает на таблицу, в которой нет поля для my_class::x()

A>    return 0;
A>}
A>


A>есть идеи как это объяснить?

См. выше комментарии.

A>P.S. если вызов copy перенести в конструктор копирывания my_str, то все работает замечательно!!!

Потому что там vfptr источника такой же, как и vfptr приёмника.

Кстати говоря, если виртуальные вызовы реализованы иным способом, нежели через vfptr, то побайтовое копирование может сломать и эту ситуацию.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.