C++ static_cast в виртуальную базу во время выполнения

Предположим, у нас есть такой код:

struct Granny {
  int g;
};
struct Mom : virtual Granny {
  int m;
};
struct Son : Mom {
  int s;
};

int main() {
  int x;
  std::cin >> x;
  Mom* mom = (x ? new Son : new Mom);
  Granny* granny = static_cast<Granny*>(mom);
}

Классы не полиморфны, поэтому у Granny нет виртуальной таблицы. Теперь, в зависимости от x, под указателем Mom может быть разное расположение памяти. Таким образом, подобъект Granny будет сдвинут от начала объекта либо на 16, либо на 12 байт.

Вопрос: статический_cast вместо «простого указателя сдвига» скомпилирован в «разыменование vptr(vtable) в объекте Mom, затем просмотрите какой-то индекс, чтобы найти виртуальное смещение, а затем, наконец, сместите указатель на это смещение»? Итак, будет ли static_cast иметь две дополнительные операции во время выполнения? Если нет, пожалуйста, объясните, что происходит.

Как вы планируете позже удалить объект, указанный mom? Еще один if с приведением обратно к Son, если понадобится? Если да, то почему бы не использовать полиморфизм? Откуда берутся кавычки «просто сдвинуть указатель» и т. д.? Я не знаю, что это значит.

Ted Lyngmo 26.07.2024 10:37

Кажется, тебя волнует производительность. Тогда вам нужно учитывать, что ваш код ничего не делает с granny и что приведение типов не должно ничего делать.

463035818_is_not_an_ai 26.07.2024 10:43

оптимизаторы - звери. Невозможно предугадать, что они сделают. Но если человек видит способ транслировать ваш код таким образом, чтобы приведение требовало 0 операций, то компилятор наверняка тоже это увидит. Также обратите внимание, что vtable — это деталь реализации. На самом деле ничто не требует от компилятора каких-либо действий с vtable или vptr.

463035818_is_not_an_ai 26.07.2024 10:45

@TedLyngmo Я понимаю, что у бабушки или мамы должен быть виртуальный деструктор. Я думаю, что цель моего вопроса — static_cast и что он делает в описанном случае. Поэтому я решил не загромождать текст и код ненужными вещами. Что касается «простого сдвига указателя», я думаю, что без виртуального наследования бабушка, мама и сын будут размещаться один за другим, поэтому static_cast в ассемблере будет просто «сдвинуть указатель мамы на x байт назад или вперед (в этом случае 0 байт)»

gh_shark 26.07.2024 10:51

@ 463035818_is_not_an_ai "похоже, тебя заботит производительность". Моя цель — понять поведение static_cast, а не найти наиболее оптимизированный способ сделать это. «Оптимизаторы — звери». Здесь я полагаю, что компилятор не может выполнять никаких оптимизаций. «vtable — это деталь реализации» Да, но теперь я полагаюсь на свои общие знания о виртуальных таблицах и наследовании. Поэтому я могу не понимать, как это работает (в таком случае, пожалуйста, объясните мне)

gh_shark 26.07.2024 10:55

тогда vtable и смещения еще менее актуальны. Поведение заключается в том, что указатель, полученный в результате приведения, указывает на подобъект Granny объекта. vtable и vptr — это не «поведение», а детали реализации, на которые нельзя полагаться.

463035818_is_not_an_ai 26.07.2024 10:58

не поймите меня неправильно. Я понимаю, откуда вы, но, по моему мнению, важно понимать ограниченность ответа, который вы ищете.

463035818_is_not_an_ai 26.07.2024 11:00

@ 463035818_is_not_an_ai Я понимаю, что это действительно абстрактный вопрос из-за реализации виртуальных таблиц, а виртуальное наследование вообще не стандартизировано. Но меня не устраивает, что «результат static_cast является указателем на Granny», я хочу знать его механизм и более подробно, что происходит под капотом, даже с impl. определенные виртуальные таблицы и т. д.

gh_shark 26.07.2024 11:15

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

463035818_is_not_an_ai 26.07.2024 11:25

Абсолютно согласен. Спасибо!

gh_shark 26.07.2024 11:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете просто бросить оба случая в проводник компилятора:

Granny* from_Son(Son* x) { return static_cast<Granny *>(x); }
Granny* from_Mom(Mom* x) { return static_cast<Granny *>(x); }

компилируется в следующие три инструкции (с проверкой ошибок):

        mov     rax, QWORD PTR [rdi]    
        add     rdi, QWORD PTR [rax-24]
        mov     rax, rdi

В этом фрагменте rdi — это x. [rdi] — это ваша виртуальная таблица, и смещение до Granny, таким образом, сохраняется за 24 байта до виртуальной таблицы.

Спасибо! Наверное, мне стоит выучить базовый ассемблер, чтобы проверить его самостоятельно и не задавать здесь такие вопросы.

gh_shark 26.07.2024 11:22

Другие вопросы по теме