Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.53/34: Рейтинг темы: голосов - 34, средняя оценка - 4.53
0 / 0 / 0
Регистрация: 11.11.2017
Сообщений: 50

Дорого ли приведение указателей?

14.11.2019, 18:19. Показов 7300. Ответов 55
Метки c++ (Все метки)

Студворк — интернет-сервис помощи студентам
Я не встретил эту тему в инете(именно про указатели, а не просто типы), но если она есть, дайте ссылку. На сколько дорога операция приведения указателя в стиле СИ? К примеру, есть два класса, один наследует другой. Дорого ли приведение указателя из указателя на родительский класс на указатель на дочерний? Я знаю, что указатель—это обычный int, который система принимает за адрес в памяти. Переменная, содержащая в себе указатель на объект представляет из себя int со значением вида 0x7f84a41000c0. Тогда, по идее, это не дорого для процессора. Я прав?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
14.11.2019, 18:19
Ответы с готовыми решениями:

Приведение указателей
В функции в качестве параметра передаю указатель на один из самых базовых классов . Затем в функции вызываю функцию, которой нет в базовом...

Приведение указателей
Вопрос немного из другого раздела, но тем не менее, вопросы не по поводу WinApi, а поводу приведения указателей. В WinApi есть функция...

приведение типов указателей
Задача у меня простая. Нужно побитно оперировать с числом unsigned int и на каких-то этапах заносить его в массив. для начала я решил,...

55
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 12:21
Студворк — интернет-сервис помощи студентам
COKPOWEHEU, IGPIGP, зачем спорить. Можно же просто провести нагрузочный тест для обоих вариантов. И проверить, сколько времени займёт миллион таких вызовов
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 12:32
Цитата Сообщение от IGPIGP Посмотреть сообщение
для запуска виртуального метода задействуется механизм выяснения (конкретизации) динамического типа.
На самом деле нет ни одной реализации, где было бы так, как вы описываете.
Виртуальность никогда не реализовывалась через RTTI и сама по себе виртуальность появилась исторически гораздо раньше, чем RTTI (разница в почти 13 лет).
2
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
21.11.2019, 12:36
Цитата Сообщение от Алексей1153 Посмотреть сообщение
COKPOWEHEU, IGPIGP, зачем спорить. Можно же просто провести нагрузочный тест для обоих вариантов. И проверить, сколько времени займёт миллион таких вызовов
Ok, - на каждом компиляторе, на каждой версии. Вопрос же топика о скорости приведений.
Можно попробовать. Но если не заставлять строки использовать придётся сравнивать два type_id? А указатель нужно лишь на на проверить. Вечером может поковыряю. А вам, как инициатору, предлагаю положить свою версию теста.

Добавлено через 3 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
На самом деле нет ни одной реализации, где было бы так, как вы описываете.
Виртуальность никогда не реализовывалась через RTTI и сама по себе виртуальность появилась исторически гораздо раньше, чем RTTI (разница в почти 13 лет).
Сейчас подумал и понял, что увлёкся.
То есть, вы полагаете, type_id и dynamic_cast реализованы по разному и type_id может быть быстрее? Спор об этом возник.
0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 12:44
IGPIGP, я не знаю точно, как именно организовать тест, чтобы всякие там кеши процессора не повлияли. Вызовы в цикле без всяких заморочек подойдут? Или лучше пересоздавать объект на каждой итерации?
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 13:00
Цитата Сообщение от IGPIGP Посмотреть сообщение
То есть, вы полагаете, type_id и dynamic_cast реализованы по разному и type_id может быть быстрее? Спор об этом возник.
Нет, я такого не говорил.

Во-первых я хотел бы сказать, что не любой typeid, также как и не любой dynamic_cast обязаны разрешаться на этапе исполнения. Если у компилятора есть вся необходимая информация, то runtime структуры с динамической информацией о типе даже не задействуются.

Во-вторых в общем смысле type_id и dynamic_cast - это части RTTI.
И тот и другой при условии динамического исполнения черпают информацию из одного источника - специальной структуры данных c динамической информацией о типе.
Вот ссылка на то, как это делается в Itanium ABI (в Windows ABI примерно так же): https://itanium-cxx-abi.github... .html#rtti

Оттуда:
Как сравниваются два typeid:
In a flat address space (such as that of the Itanium architecture), the operator==, operator!=, and before() members are easily implemented in terms of an address comparison of the name NTBS.
Как реализован dynamic_cast:
https://itanium-cxx-abi.github... -algorithm
Т.е. никакого сравнения строк нет, и нет даже поиска по хеш-таблице, как в более ранних реализациях.
2
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 13:20
в общем, насчёт корректности теста не уверен, критикуйте
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <chrono>
#include <iostream>
 
class A
{
    int f1=0;
public:
    virtual ~A()
    {
    }
};
 
class B:public A
{
public:
    virtual ~B()
    {
    }
};
 
int main()
{
    const int64_t iters=10000000;
    std::cout<<"iters: "<<iters<<std::endl;;
    {
        auto start = std::chrono::system_clock::now();
        for(int64_t i=0; i<iters; i++ )
        {
            A* a=new B();
 
            auto* b=dynamic_cast<B*>(a);
 
            delete a; a=0;
        }
        auto end = std::chrono::system_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
        std::cout<<"dynamic_cast: "<<elapsed<<" ms"<<std::endl;
    }
 
    {
        auto start = std::chrono::system_clock::now();
        for(int64_t i=0; i<iters; i++ )
        {
            A* a=new B();
 
            const std::type_info& info=typeid(*a);
            //std::string s=info.name();
 
            delete a; a=0;
        }
        auto end = std::chrono::system_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
        std::cout<<"typeid: "<<elapsed<<" ms"<<std::endl;;
    }
 
    system("pause");
    return 0;
}
MinGW 5.3.0 32bit , запускал в дебаге, результат:

iters: 10000000
dynamic_cast: 1288 ms
typeid : 1168 ms
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 13:36
Алексей1153, во-первых участие в замере динамической аллокации сводит на нет всю достоверность.

А что вы хотели этим тестом показать? Можете словами сформулировать?
0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 13:41
DrOffset, лично я - ничего не собирался показывать https://www.cyberforum.ru/post14016822.html
Но разница между двумя интервалами показывает, что выполняется быстрее, поскольку всё остальное в циклах одинаковое.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 13:52
Цитата Сообщение от Алексей1153 Посмотреть сообщение
лично я - ничего не собирался показывать
Ну как же, вы предложили разрешить спор через замер. Значит вы знаете что нужно замерить, чтобы склонить чашу весов в ту или иную сторону. Вот я и спросил, что именно вы меряете?

Цитата Сообщение от Алексей1153 Посмотреть сообщение
поскольку всё остальное в циклах одинаковое.
Это не так. У вас там аллокации. Которые никто не обязывал отрабатывать за одинаковое время. И замеряете вы в дебаге, а там могут быть всякие проверки, которые замедляют выполнение. Это безотносительно сути замера.
Но это даже не важно здесь.
Важнее понять что именно мы меряем.

Вот у нас есть typeid. Что это? Это получение указателя на type_info из VTBL.
Код с typeid условно такой:
C++
1
std::type_info * info = a->vptr->ptypeinfo;
И все. Вот именно это вы и меряете.

Код с dynamic_cast условно такой:
C++
1
2
std::type_info * info = a->vptr->ptypeinfo;
b = someoffsetalgo(info, a); // см. ссылку выше
Ну так и давайте спросим, как можно сравнивать получение указателя с какой-то выполняемой логикой с использованием данных по этому казателю? Что это дает-то? Это разные же действия, с разной семантикой, с разным результатом.
1
 Аватар для COKPOWEHEU
4079 / 2677 / 432
Регистрация: 09.09.2017
Сообщений: 11,888
21.11.2019, 14:05
Цитата Сообщение от IGPIGP Посмотреть сообщение
COKPOWEHEU, боюсь, по какой-то фундаментальной причине мы не можем тут друг друга понять.
Для работы механизма таблицы виртуальных функций нет нужды в знании типа. Меня самого заинтересовала эта задача, так что набросал демонстрационный код (АХТУНГ! код кишит неопределенным поведением и старательно использует внутренности g++. Он может вызвать сегфолт, поломать чужую память и погрызть тапки!)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <string.h>
 
//объявляем родительский класс с виртуальными полями
class cCl{
public:
  int field;
  cCl(){field = 1;}
  virtual void func(){printf("cCl\n");}
  virtual int func2(int a, int b){printf("cCl(%i, %i) ", a, b); return a+b+field;}
};
 
//объявляем дочерний класс с не менее виртуальными полями
class cChild:public cCl{
public:
  cChild(){field = 2;}
  virtual void func(){printf("cChild\n");}
  virtual int func2(int a, int b){printf("cChild(%i, %i) ", a, b); return a-b+field;}
};
 
//прототипы "методов"
typedef void (cCl_func)(cCl*);
typedef int (cCl_func2)(cCl*, int, int);
 
//хакерская структура для получения доступа к внутренностям классов
struct sCl{
  void **fn; //таблица виртуальных функций!
  int field; //поля класса (для демонстрации не обязательны)
};
 
void test(cCl *self){printf("test\n");}
 
int main(){
  cCl *sample = new cCl; //создаем "чистый" экземпляр родителя
  cCl *virt = new cChild; //создаем потомка через наследование
  cChild *child = new cChild; //создаем "чистого" потомка
  sCl *str;
  int res;
  
  //влезаем во внутренности родителя
  str = (sCl*)sample;
  printf("Sample: ");
  ((cCl_func*)str->fn[0])(sample); //ТАДАМ! Мы вызвали виртуальный метод func
  res = ((cCl_func2*)str->fn[1])(sample, 2, 1); //ТАДАМ! Мы вызвали виртуальный метод func2 даже с параметрами
  printf("%i\n", res);
  printf("\n");
  
  str = (sCl*)virt;
  printf("Virt  : ");
  ((cCl_func*)str->fn[0])(virt);
  res = ((cCl_func2*)str->fn[1])(virt, 2, 1);
  printf("%i\n", res);
  printf("\n");
  
  str = (sCl*)child;
  printf("Child : ");
  ((cCl_func*)str->fn[0])(child);
  res = ((cCl_func2*)str->fn[1])(child, 2, 1);
  printf("%i\n", res);
  printf("\n");
  
  
  str->fn = ((sCl*)sample)->fn;
  printf("Hacked: ");
  child->func();
  res = child->func2(2,1);
  printf("%i\n", res);
  str->fn = ((sCl*)child)->fn;
  
  
  //не забываем прибраться за собой!
  delete child;
  delete virt;
  delete sample;
}
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
$ g++ main.c
$ ./a.out 
Sample: cCl
cCl(2, 1) 4
 
Virt  : cChild
cChild(2, 1) 3
 
Child : cChild
cChild(2, 1) 3
 
Hacked: cCl
cCl(2, 1) 5
TL; DR: перед явными полями классов есть еще указатель на массив виртуальных функций, из которого при некотором извращении их можно вызвать просто по индексам. Примерно так же это работает и в штатном режиме: если функция не-виртуальная, компилятор тупо подставляет фиксированный адрес, если же виртуальная - вызывает по номеру из массива. Более того, адрес этой таблицы можно даже подменить! Это и продемонстрировано в последнем вызове, когда объект cChild вдруг начинает считать себя cCl'ом (но вот поле field у него сохраняется).
Собственно, именно отсюда берется "лишний переход по указателю", о котором я говорил с самого начала.
1
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 14:12
DrOffset, про корректность теста я выше сразу написал - что я не уверен в ней.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 14:14
Цитата Сообщение от Алексей1153 Посмотреть сообщение
про корректность теста я выше сразу написал - что я не уверен в ней.
Ну вот я вам показал, надеюсь, в чем именно проблема.
Просто сначала я хотел чтобы вы сами к этому пришли. Если бы вы начали формулировать словами достаточно строго смысл ваших замеров, то сами столкнулись бы с противоречием.
0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 14:26
DrOffset, ну так в итоге то что, получается, нужно оставить циклы вот в таком виде и запускать в релизе?


C++
1
2
3
4
5
6
7
8
9
        for(int64_t i=0; i<iters; i++ )
        {
             auto* b=dynamic_cast<B*>(a);
        }
 
        for(int64_t i=0; i<iters; i++ )
        {
            const std::type_info& info=typeid(*a);
        }
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
21.11.2019, 15:54
Цитата Сообщение от Алексей1153 Посмотреть сообщение
нужно оставить циклы вот в таком виде и запускать в релизе?
Нет. Это же разные действия.
Сравнивать имеет смысл только эквивалентные по результату действия. Например два алгоритма сортировки. Результат одинаковый, процессы разные. Вот можно их сравнить. А тут?

Добавлено через 3 минуты
Ну хорошо, допустим мы сравнили, избавились от излишней оптимизации, оставили нужную - получили результат.
Как это докажет или опровергнет позицию одной из сторон?

Не по теме:

В вашей текущей реализации просто исходя из количества действий первый цикл всегда будет медленнее, чем второй. Можно даже не мерить ничего. Но что это значит в контексте спора? Мне вот ответ на этот вопрос не очевиден совсем.

0
фрилансер
 Аватар для Алексей1153
6441 / 5635 / 1127
Регистрация: 11.10.2019
Сообщений: 14,981
21.11.2019, 16:07
DrOffset, в общем, понятно, работает вечное правило оптимизации - сначала нужно доказать, что оптимизация нужна, только потом начинать замерять и оптимизировать
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
22.11.2019, 00:02
Цитата Сообщение от Dimgo2 Посмотреть сообщение
На сколько дорога операция приведения указателя в стиле СИ?
Преобразование указателей в стиле С в языке С++ - слишком универсальная операция. Она может быть

1. Чисто концептуальной: не порождать кода вообще, т.е. быть бесплатной

2. Производить сдвиг указателя на значение времени компиляции. Так как язык требует, чтобы null-указатель превращался именно null-указатель, такой сдвиг должен еще сопровождаться проверкой на null. Это уже дороже, но все равно относительно дешево.

3. Производить модификацию значения указателя на значение времени выполнения. Такое возможно при преобразованиях указателей на члены класса (хотя они формально не являются "указателями").

4. Выполнять относительно "тяжелые" обращения к структурам в памяти, например, при преобразовании указателей в иерархии с виртуальным наследованием. Опять же, оговорка про null имеет место и здесь.

Так что все зависит от контекста.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.11.2019, 00:02
Помогаю со студенческими работами здесь

Приведение указателей в стиле си
Здравствуйте, это наверное самый дурацкий вопрос но что значит скобочки в c++ т.е вот например дан код: void* p = (int *)&amp;ip; и...

Неявное приведение указателей на классы
Всем привет! Обнаружилась вот такая нестыковочка: имеем интерфейсный класс IIn. И имеем класс-наследник ExtIn : public IIn далее...

Приведение типов умных указателей
Добрый день. Реализовал простенький умный указатель с подсчетом ссылок. template&lt;typename object_t&gt; class Ptr { ...

Отличие приведение типов указателей
Чем отличаются при Base* a_ptr = new Derivered(); следующие строки: A) auto ptr = static_cast&lt;Derived*&gt;( a_ptr ); B) auto ptr =...

Объяснить, что происходит в коде (приведение одного типа указателей к другому?)
char* a = &quot;Hell&quot;; int* b =(int*) a; cout &lt;&lt; *b; Как я понимаю в этом кусочке кода происходит преобразование одного типа...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
56
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru