Здравствуйте, remark, Вы писали:
К>>Окей, тогда вот такой код
R>Занятный пример. Честно говоря, я не помню, что бы когда-либо сталкивался с adjustor служебной функцией.
Наверное, .asm-файлы редко смотрел и vftable не потрошил
R>Наверное adjustor всё равно эффективнее смещения this в месте вызова.
Для множественного перекрытия — это единственный выход (не считая извращений).
Поскольку Z::f перекрывает и X::f, и Y::f — она должна присутствовать в обеих таблицах.
Очевидно, что одно из этих присутствий опосредуется переходником, который корректно даункастит.
Вот если бы мы сделали
struct W { virtual void* e()=0; };
struct X { virtual void* f()=0; };
struct Y { virtual void* f()=0; };
struct Z : W, X, Y
{
void* e() { return this; }
void* f() { return this; }
void* g() { return this; }
};
То вместо двух переходников (Z::X::f и Z::Y::f), кастящих к Z*, можно обойтись одним.
И действительно, Студия так и делает.
Z z;
z.e(); // кастинг Z->W тривиальный
z.f(); // кастинг Z->X (+4), в теле кастинг X->Z по месту (-4)
z.g(); // кастинг Z->Y (+8), в теле кастинг Y->Z по месту (-8)
Y& y = z; // Z->Y (+8)
y.f(); // в точке вызова кастинга нет, в переходнике кастинг Y->Z->X (-8+4 = -4), в теле кастинг X->Z по месту (-4)
y.g(); // в точке вызова кастинга нет, в теле кастинг Y->Z по месту (-8)
Здравствуйте, Bell, Вы писали:
R>>Честно говоря, я немного затрудняюсь с ходу трактовать 4.10/2
B>Честно говоря, мне уже совсем не кажется, что дело в этом пункте. B>Вернее даже так — дело совсем не в стандартном преобразовании к void*.
В стандарте же не говорится, в каком виде this передавать. Конвенция thiscall — личное дело компилятора.
Вот захотел передавать на стеке и со смещением — ради бога.
Поскольку this — это значение, нигде официально не размещённое, то проверить его устройство мы не можем.
— Почему у твоей таксы такие короткие лапы?
— До земли достают, ну и достаточно.
Здравствуйте, remark, Вы писали:
R>Вообще изначально вопрос возник при разбирательстве, почему в следующем коде equal получается равным true. Это было бы логично, если бы статические типы this и other различались, ну там приведение между базовым и производным типами. А тут получается, что статические типы одинаковые, однако 2 физических не равных указателя при сравнении дают true. R>
R>void T::f()
R>{
R> T* other = ...;
R> // assume this = 0x1000, and other = 0x2000
R> bool equal = (this == other);
R> ...
R>}
R>
Звучит как бред. Можешь привести рабочий пример, который валится на ассерте, хотя и не должен?
Или код и не должен валиться, но дебаггер при этом показывает ерунду?
Здравствуйте, Кодт, Вы писали:
К>Звучит как бред. Можешь привести рабочий пример, который валится на ассерте, хотя и не должен? К>Или код и не должен валиться, но дебаггер при этом показывает ерунду?
Да, никакой код не валится. В итоге всё работает корректно. Я даже попытался дополнительно поломать код с помощью каких-то преобразований к void* и uintptr_t, но ничего не получилось. Пробовал делать типа такого:
uintptr_t p = (uintptr_t)this;
T* x = (T*)p;
assert(this == x);
Это работает как и ожидается, т.е. компилятор делает смещение при конвертации this к uintptr_t.
Однако дебаггер показывает различные адреса объектов, и в ассемблере они различны. Это и вызвано недоумение.
Кстати дебаггер корректно показывает содержимое объекта. Т.е. внутри X::foo() мы имеем this указывающий на другой объект Y, но дебаггер корректно показывает члены объект Х по такому указателю, т.е. он тоже неявно делает это смещение.
Здравствуйте, remark, Вы писали:
R>Я думаю, что через 5 минут после публикации вопроса нецелесообразно давать какие-либо подсказки, т.к. это будет нечестно по отношению к тем, кто хочет выдать свой ответ без каких-либо подсказок.
Миль пардоньте, не догнал, что это cup of coffee task.
Но вы сами виноваты, могли бы с множественным и виртуальным наследованием поиграться, да еще и не на ia32 платформе, чтобы уши указателя не торчали так явно
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, remark, Вы писали:
R>>Я думаю, что через 5 минут после публикации вопроса нецелесообразно давать какие-либо подсказки, т.к. это будет нечестно по отношению к тем, кто хочет выдать свой ответ без каких-либо подсказок.
А>Миль пардоньте, не догнал, что это cup of coffee task. А>Но вы сами виноваты, могли бы с множественным и виртуальным наследованием поиграться, да еще и не на ia32 платформе, чтобы уши указателя не торчали так явно
Тут идёт смещение не на размер указателя, а на размер объекта. Т.е. добавив здесь
в один из объектов большой массив, можно получить смещение сколь угодно большое. Соотв. сделав смещение 4, я как раз стремился запутать ситуацию, типа смещение идёт на размер какого-то указателя. Если бы смещение было, например, 1234h, то было бы очевидно, что идёт смещение на размер объекта, а это уже даёт какую-то информацию. У меня же смещение идёт на какие-то абстрактные 4... Ну хотя, что кому будет сложнее наверное субъективно. Кого-то бы может наоборот 1234h ввело бы в ступор...