используя библиотеку 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, то все работает замечательно!!!
Здравствуйте, alex2077, Вы писали:
A>есть идеи как это объяснить?
у производного класса добавилось два виртуальных метода, поэтому sizeof(my_str) != sizeof(my_class), и это в любом случае не podo типы
поэтому копирование через copy(...), где кстати происходит приведение this к базовому классу, не будет корректным
Здравствуйте, alex2077, Вы писали:
A>есть идеи как это объяснить? A>P.S. если вызов copy перенести в конструктор копирывания my_str, то все работает замечательно!!!
А что тут объяснять?
Полиморфные классы с наследованием -- это далеко не POD, так что по memcpy он копироваться и не должен.
Если конкретнее проблему разобрать, то во время работы конструктора базы указатель на таблицу виртуальных функции соответсвует базе, а при работе конструктора наследника -- наследника.
Соответсвенно компилятор генерит там код, который указатели переписывает. И если ты по ходу пьесы туда влезешь с memcpy, то может быть всё что угодно...
А когда ты конструируешь копию, то все указатели уже совпадабют и в этой реализации тебе везёт и ничего плохого не происходит...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, 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, а непосредственно в массив.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
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, то побайтовое копирование может сломать и эту ситуацию.