Вызов перегруженной функции - Segmentation fault

153
24 октября 2018, 11:20

При вызове Func() заполняется buffer данными из сокета, после происходит их конвертация в класс Derived. Если после конвертаци вызвать функию Foo(), то происходит ошибка сигментации. Если создавать класс в стеке, то ошибка не происходит.

header file

class Interface
{
public:
    virtual char Foo() = 0;
};
class Derived : public Interface
{
public:
    char Foo() override
    {
        return val[0];
    }
    char val[10];
};

source file

boost::array<char, 8192> buffer;
void Func()
{
...
auto derived = std::make_shared<Derived>();
 std::memcpy(derived.get(), buffer.data(), sizeof(Derived));
 derived->Foo(); // Segmentation fault
...
}
Answer 1

Вообще, ИМХО, так лучше никогда не делать: записывать в объект побайтово какую-то последовательность байт, беря при этом указатель на начало объекта. Вот смотрите: если бы у вас это был простенький класс, то все бы работало как вы и ожидали (на сколько я могу судить), но вот вы унаследовались... Тоже вроде все должно работать, но у вот только у вас есть виртуальный метод - это все меняет. Можете сами убедится, для этого просто проверьте sizeof. Думаю вы удивитесь, тому что размер оказался больше, чем если бы не было виртуального методы. Дело в том, что компилятор должен как-то определять, какой метод дернуть, а если у вас есть виртуальные методы то как это сделать? Раз так, объект класса должен хранить указатель на таблицу функций (извиняюсь за неточность формулировки), которые он может и должен вызывать. Получается что вы переписываете указатель на эту таблицу, и объект обращается по невалидному указателю.

Вообщем: либо используйте метод для записи (собственно для чего и создавались классы), либо берите указатель именно на член класса, который нужно изменить и перезаписывайте исходя из его размера. Но второй вариант абсолютно претит принципам инкапсуляции.

READ ALSO
Ошибка при вызове деструктора

Ошибка при вызове деструктора

помогите разобраться с проблемой, она довольно распространенная и на форуме куча сообщений про это но в моей программе я никак не могу найти...

175
sqlite3_open не получаетсяоткрыть базу в явно указанной директории

sqlite3_open не получаетсяоткрыть базу в явно указанной директории

ОС - Windows Кодировка входной строки - неизвестна, но скорее всего виндовская будетКодировка файлов проекта - набор символов юникода

198
EntityManager persist() не сохраняет данные в БД ( PostgreSQL )

EntityManager persist() не сохраняет данные в БД ( PostgreSQL )

При нажатии на кнопку Register должен добавляться новый пользователь в БДКонсоль выдает :

176