Информация об изменениях

Сообщение Re[3]: Получение адреса объекта по адресу члена этого объект от 11.12.2022 13:22

Изменено 11.12.2022 13:23 okman

Re[3]: Получение адреса объекта по адресу члена этого объекта
Здравствуйте, maks1180, Вы писали:

M>Я не пойму в чём проблема если у класса есть фиртуальная функция? разница лишь только в том, что в начале класса добавляется указатель на v-table, все переменные класса сдвигаются на размер указателя.


Есть некоторые кейсы, при которых offsetof не может корректно отработать. Сразу приходит на ум виртуальное наследование.
Да, это экзотика, которая редко встречается, но это вполне легальная часть C++. И компиляторы обычно ругаются на такое.
Можно придумать примерно такой кейс:
#include <cstdio>

struct Base
{
    virtual ~Base() {}
    int m_val;
};

struct Left : virtual Base
{
    void showOffset()
    {
        printf("%zu\n", (size_t)&m_val - (size_t)this);
    }
};

struct Right : virtual Base
{
};

struct Child : Left, Right
{
};

int main()
{
    Left left;
    left.showOffset();
    
    Child child;
    child.showOffset();
    
    return 0;
}

Clang и GCC выводят 16 и 24. MSVC — 8 и 12. Ну т.е. offset от 'Left' до 'm_val' здесь зависит от того, как класс Left
включен в наследование — при виртуальном наследовании эта информация должна вычисляться динамически, т.е. в рантайме.
Re[3]: Получение адреса объекта по адресу члена этого объект
Здравствуйте, maks1180, Вы писали:

M>Я не пойму в чём проблема если у класса есть фиртуальная функция? разница лишь только в том, что в начале класса добавляется указатель на v-table, все переменные класса сдвигаются на размер указателя.


Есть некоторые кейсы, при которых offsetof не может корректно отработать. Сразу приходит на ум виртуальное наследование.
Да, это экзотика, которая редко встречается, но это вполне легальная часть C++. И компиляторы обычно ругаются на попытку применить offsetof к таким классам.
Можно придумать примерно такой кейс:
#include <cstdio>

struct Base
{
    virtual ~Base() {}
    int m_val;
};

struct Left : virtual Base
{
    void showOffset()
    {
        printf("%zu\n", (size_t)&m_val - (size_t)this);
    }
};

struct Right : virtual Base
{
};

struct Child : Left, Right
{
};

int main()
{
    Left left;
    left.showOffset();
    
    Child child;
    child.showOffset();
    
    return 0;
}

Clang и GCC выводят 16 и 24. MSVC — 8 и 12. Ну т.е. offset от 'Left' до 'm_val' здесь зависит от того, как класс Left
включен в наследование — при виртуальном наследовании эта информация должна вычисляться динамически, т.е. в рантайме.