Re: Проверить тип void*
От: TarasB  
Дата: 03.01.14 11:14
Оценка: -8
Здравствуйте, enji, Вы писали:

E>Хочется узнать, указывает ли void* на конкретный тип

Крестопроблемы отсутствия общего предка в иерархии, да?
Re: Проверить тип void*
От: Vamp Россия  
Дата: 03.01.14 16:38
Оценка: +5
Нет способа. И незачем.
Да здравствует мыло душистое и веревка пушистая.
Re: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 03.01.14 12:55
Оценка: +3
Здравствуйте, enji, Вы писали:

E>Хочется узнать, указывает ли void* на конкретный тип


Почему у тебя void*, а не Base*, для начала?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Проверить тип void*
От: zverjuga Беларусь  
Дата: 03.01.14 16:13
Оценка: -2
dynamic_cast ?
проклятый антисутенерский закон
Re[5]: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 04.01.14 13:52
Оценка: 1 (1)
Здравствуйте, enji, Вы писали:

E>Здравствуйте, jazzer, Вы писали:


J>>А почему бы в таком случае не использовать boost::function напрямую (или вообще boost::signal)? Он шаблонов не требует, у него тип нормальный, а в замыкание при конструировании что угодно можно засунуть, не нужно никаких дополнительных void*-параметров.


E>велосипедостроение потому что boost::signal напрямую использовать не получится — хочется фильтрацию и приоритеты вызовов. function кушает 16 байт и дает вызов по указателю на член + вызов виртуальной функции. Мои два указателя кушают 8 байт и дают простой вызов функции по указателю. Хотя конечно function значительно более удобен для оборачивания всяких лямбд. Может быть и перееду в конце концов на него.


Если ты знаешь, какие типы могут быть, и при этом не хочешь наследовать все от одного базового типа, но знаешь все возможные базы — попробуй boost::variant с этим набором возможных базовых типов.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Проверить тип void*
От: Кодт Россия  
Дата: 05.01.14 14:01
Оценка: 1 (1)
Здравствуйте, enji, Вы писали:

E>Хочется узнать, указывает ли void* на конкретный тип

E>По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...

В общем случае, это невозможно, void* — это слишком хорошо стёртый тип. Особенно, с учётом того, что можно взять указатель на неполиморфную базу полиморфного наследника — она ничем не отличается от члена-данного, кроме тайного знания, что это не член, а база.

Если класс полиморфный, то обычная практика — поместить vfptr в самое начало лэяута. (Это не оговаривается стандартом, так же, как не оговаривается вообще механизм виртуальных функций и rtti; но MS- и linux-совместимые компиляторы делают именно так).
При этом неполиморфные базы смещаются, а если есть несколько полиморфных баз — то первая из них будет с нулевым смещением, а остальные со своими vfptr-ами — как придётся.

(Тут я хотел написать много слов про dynamic_cast, в том числе про dynamic_cast<void*>, но проще будет отослать к первоисточникам и толкованиям — стандарту и Страуструпу).

Разумеется, dynamic_cast применительно к неполиморфным объектам — это неопределённое поведение. Потому что, представьте себе, что там по нулевому смещению находится указатель на какую-нибудь мусорную таблицу виртуальных функций. Можно получить всё, что угодно, от защиты памяти до исполнения произвольного кода.

Отсюда мораль
— или сдерживать себя и ограничиться какой-нибудь строгой иерархией (не void*, а MyRootType*)
— или сделать внешнюю информацию о типе — хоть boost::any, хоть tagVARIANT рядом держать, — способов много
Перекуём баги на фичи!
Проверить тип void*
От: enji  
Дата: 03.01.14 09:46
Оценка:
Хочется узнать, указывает ли void* на конкретный тип

struct Base {
  virtual void ~Base() {}
};

struct Derived : Base {};

bool isBase(void *ptr) {
  // ???
}

Base b;
Derived d;
int i;
isBase(&b); // true
isBase(&d); // true
isBase(&i); // false


Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.

По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...
Re: Проверить тип void*
От: nen777w  
Дата: 03.01.14 10:12
Оценка:
E>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.
E>По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...

Абстрактный виртуальный kind_of в базовом классе.
Типа:

enum ST {
    eS2, eS3
};

struct S {
    virtual ST kind_of() const = 0;
};

struct S2 : S {
    virtual ST kind_of() const { return eS2; }
};

struct S3 : S {
    virtual ST kind_of() const { return eS3; }
};

int main(int argc, char* argv[])
{
    S2 s;
    S3 s2;
    void *p = &s;
    void *p2 = &s2;

    ST a = ((S*)p)->kind_of();
    ST b = ((S*)p2)->kind_of();
    
    return 0;
}



Но ИМХО стремно это как то, если потерять контроль над кодом.
Re[2]: Проверить тип void*
От: enji  
Дата: 03.01.14 11:04
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Абстрактный виртуальный kind_of в базовом классе.

Это все конечно здорово, вот только не всегда работает

ST kindOf(void* p) { return ((S*)p)->kind_of(); }

int i;
kindOf(&i); // упс

struct One { int t; };
struct Two : One, S2 {};
Two t;
kindOf(&t); // если Two хранится в памяти как (One, S2) - будут грабли
Re[2]: Проверить тип void*
От: Abyx Россия  
Дата: 03.01.14 12:36
Оценка:
Здравствуйте, TarasB, Вы писали:

TB>Здравствуйте, enji, Вы писали:


E>>Хочется узнать, указывает ли void* на конкретный тип

TB>Крестопроблемы отсутствия общего предка в иерархии, да?

конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект
только как производительностью запахнет — так сразу С да С++
In Zen We Trust
Re[3]: Проверить тип void*
От: TarasB  
Дата: 03.01.14 13:20
Оценка:
Здравствуйте, Abyx, Вы писали:

A>конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект

A>только как производительностью запахнет — так сразу С да С++

Ок, а почему нельзя вызвать typeid?
Re[4]: Проверить тип void*
От: Abyx Россия  
Дата: 03.01.14 14:08
Оценка:
Здравствуйте, TarasB, Вы писали:

A>>конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект

A>>только как производительностью запахнет — так сразу С да С++

TB>Ок, а почему нельзя вызвать typeid?


typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.
In Zen We Trust
Re: Проверить тип void*
От: Evgeny.Panasyuk Россия  
Дата: 03.01.14 15:16
Оценка:
Здравствуйте, enji, Вы писали:

E>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.


Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any?

E>По идее можно проверить vptr, но к нему кроскомпиляторно не подберешься, да и всякие случаи вроде множественного наследования...


Да и не поможет он в общем случае. void* может указывать на double, который случайно может выглядеть как правильный vptr.
Re[5]: Проверить тип void*
От: TarasB  
Дата: 03.01.14 15:21
Оценка:
Здравствуйте, Abyx, Вы писали:
A>typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.

Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*?
И typeid надо брать не от указателя, а от того, что по нему.
Re[6]: Проверить тип void*
От: Abyx Россия  
Дата: 03.01.14 16:22
Оценка:
Здравствуйте, TarasB, Вы писали:

TB>Здравствуйте, Abyx, Вы писали:

A>>typeid вернет "void*" потому что оно не знает где брать RTTI для объекта.

TB>Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*?

TB>И typeid надо брать не от указателя, а от того, что по нему.

ты вообще знаешь как работает RTTI?
In Zen We Trust
Re[7]: Проверить тип void*
От: niXman Ниоткуда https://github.com/niXman
Дата: 03.01.14 17:34
Оценка:
Здравствуйте, Abyx, Вы писали:

TB>>Почему нельзя все объекты, для которых ты хочешь знать тип, унаследовать от MyBaseRootObject, и вместо void* брать MyBaseRootObject*?

TB>>И typeid надо брать не от указателя, а от того, что по нему.

A>ты вообще знаешь как работает RTTI?


яркое доказательство того, кому на самом деле не нравится С++ =)
зы
TarasB — один из самых ярых ненавистников С++ на говноког.ру
(сужу не только по нику)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 03.01.14 17:43
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, enji, Вы писали:


E>>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.


EP>Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any?


boost::any не умеет доставать указатели по иерархии, только в точности то, что туда положили. Есть попытка dynamic_any (гугл в помощь), но там какие-то принципиальные сложности были, ЕМНИП, я помню было обсуждение в буст-листе, по наводке alnsn

Еще можно boost::variant, если известен набор возможных базовых классов.

Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.
Либо действительно завести реестр, но компилировать его, естественно, только в отладочной версии.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: Проверить тип void*
От: Evgeny.Panasyuk Россия  
Дата: 03.01.14 19:40
Оценка:
Здравствуйте, jazzer, Вы писали:

E>>>Понятно, что можно завести реестр объектов и проверять указатель на принадлежность, но хотелось бы обойтись без этого.

EP>>Где и почему происходит переход к void*? Возможно этот переход можно заменить на что-то типа boost::any?
J>boost::any не умеет доставать указатели по иерархии, только в точности то, что туда положили. Есть попытка dynamic_any (гугл в помощь), но там какие-то принципиальные сложности были, ЕМНИП, я помню было обсуждение в буст-листе, по наводке alnsn

Да, any_cast требует точного типа. Я имел ввиду своё type-erasure (возможно на Boost.TypeErasure), которое даст возможность неинтрузивно сделать все необходимые проверки, выполнить все операции, но:

J>Еще можно boost::variant, если известен набор возможных базовых классов.


этот вариант лучше/проще.

Кстати, наткнулся на вот это обсуждение (ты про него говорил? там и alnsn отметился).
Там is_derived проверка делается через abuse исключений.

J>Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.


Никогда не делал проверки в подобных местах — не было таких требований надёжности.
Re[2]: Проверить тип void*
От: enji  
Дата: 04.01.14 09:44
Оценка:
Здравствуйте, TarasB, Вы писали:

TB>Здравствуйте, enji, Вы писали:


E>>Хочется узнать, указывает ли void* на конкретный тип

TB>Крестопроблемы отсутствия общего предка в иерархии, да?

да как скзать. С одной стороны — да, с другой — тут погоня за миниоптимизациями, которые в "некрестах" просто невозможны Можно было сделать это все в плюсовом стиле на boost::signals2 к примеру, таких проблем бы не возникло
Re[2]: Проверить тип void*
От: enji  
Дата: 04.01.14 09:56
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Почему у тебя void*, а не Base*, для начала?


Есть собственный мини-фреймворк для сигналов-слотов, с разными плюшками, вроде предобработки сигнала, фильтрации и т.д. Пока сделал его так, что наследование от Base (да и к тому ж виртуального Base) не требуется ни для источника, ни для получателей. И по пути boost::function (с наворачиванием шаблонного наследника интерфейса) идти пока не охота — обошелся просто указателями на объект и на статическую функцию.

Дальше в рамках решения прикладной задачи захотелось написать универсальный фильтр, которому как раз хорошо бы понять тип получателя. Пока обошелся просто внешним реестром. Но задумался, нельзя ли понять тип динамически, исследую структуру объекта, на который указывает void*
Re[3]: Проверить тип void*
От: enji  
Дата: 04.01.14 10:07
Оценка:
Здравствуйте, jazzer, Вы писали:


J>Но если этот void* — это просто замыкание в стиле Си (коллбэк + контекст) или какой-нть GetWindowLong (если я правильно помню заклинание), то, имхо, ничего тут проверять не надо, достаточно просто в документации написать, что по этому указателю обязан быть наследник Base.


Вот кстати тож интересный вопрос
struct Base { 
  virtual ~Base(); 
  virtual int f();
};

struct Some { int a; };

struct S1 : Some, Base {} s1;
struct S2 : Base {} s2;
struct S3 : Base, Some {} s3;

int  func(void *o) {
  return static_cast<Base*>(o)->f();
}

func(&s1); // упс
func(&s2); // ок
func(&s3); // скорее всего ок


Как я понимаю, на msvc и gcc надо потребовать, чтобы Base был "первым" наследником
Re[3]: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 04.01.14 11:55
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, jazzer, Вы писали:


J>>Почему у тебя void*, а не Base*, для начала?


E>Есть собственный мини-фреймворк для сигналов-слотов, с разными плюшками, вроде предобработки сигнала, фильтрации и т.д. Пока сделал его так, что наследование от Base (да и к тому ж виртуального Base) не требуется ни для источника, ни для получателей. И по пути boost::function (с наворачиванием шаблонного наследника интерфейса) идти пока не охота — обошелся просто указателями на объект и на статическую функцию.


А почему бы в таком случае не использовать boost::function напрямую (или вообще boost::signal)? Он шаблонов не требует, у него тип нормальный, а в замыкание при конструировании что угодно можно засунуть, не нужно никаких дополнительных void*-параметров.

E>Дальше в рамках решения прикладной задачи захотелось написать универсальный фильтр, которому как раз хорошо бы понять тип получателя. Пока обошелся просто внешним реестром. Но задумался, нельзя ли понять тип динамически, исследую структуру объекта, на который указывает void*


Нет, нельзя. dynamic_cast мог бы, но он не работает с void*, ему нужен указатель на объект реального класса.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Проверить тип void*
От: enji  
Дата: 04.01.14 13:25
Оценка:
Здравствуйте, jazzer, Вы писали:

J>А почему бы в таком случае не использовать boost::function напрямую (или вообще boost::signal)? Он шаблонов не требует, у него тип нормальный, а в замыкание при конструировании что угодно можно засунуть, не нужно никаких дополнительных void*-параметров.


велосипедостроение потому что boost::signal напрямую использовать не получится — хочется фильтрацию и приоритеты вызовов. function кушает 16 байт и дает вызов по указателю на член + вызов виртуальной функции. Мои два указателя кушают 8 байт и дают простой вызов функции по указателю. Хотя конечно function значительно более удобен для оборачивания всяких лямбд. Может быть и перееду в конце концов на него.

Однако к первоначальному вопросу это отношения не имеет — хотелось определять тип источника сигнала и предпринимать некоторые действия в зависимости от этого.

Судя по этой теме, никакой волшебной пули нет — или надо в качестве источника иметь некий объект с доп информацией, или внешний реестр источников.
Re[4]: Проверить тип void*
От: TarasB  
Дата: 04.01.14 18:41
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Нет, нельзя. dynamic_cast мог бы, но он не работает с void*, ему нужен указатель на объект реального класса.


Ну так подсунь ему не void* а BasicRootClassOfAllClasses, все нужные классы наследуй от него.
Re[5]: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 05.01.14 10:38
Оценка:
Здравствуйте, TarasB, Вы писали:

TB>Здравствуйте, jazzer, Вы писали:


J>>Нет, нельзя. dynamic_cast мог бы, но он не работает с void*, ему нужен указатель на объект реального класса.


TB>Ну так подсунь ему не void* а BasicRootClassOfAllClasses, все нужные классы наследуй от него.


у него там int в примере есть, как нафиг BasicRootClassOfAllClasses
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Проверить тип void*
От: TarasB  
Дата: 05.01.14 11:02
Оценка:
Здравствуйте, jazzer, Вы писали:

J>у него там int в примере есть, как нафиг BasicRootClassOfAllClasses


Пусть обернёт в класс тогда этот свой инт.
Re[7]: Проверить тип void*
От: jazzer Россия Skype: enerjazzer
Дата: 05.01.14 11:23
Оценка:
Здравствуйте, TarasB, Вы писали:

TB>Здравствуйте, jazzer, Вы писали:


J>>у него там int в примере есть, как нафиг BasicRootClassOfAllClasses


TB>Пусть обернёт в класс тогда этот свой инт.


Зачем?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[8]: Проверить тип void*
От: TarasB  
Дата: 05.01.14 12:01
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Зачем?


Чтобы отличить указатель на Int от указателя на Base. Ну, если ему это нужно. Если не нужно, то к чему твоё замечание про int?
Re[5]: Проверить тип void*
От: Erop Россия  
Дата: 07.01.14 12:28
Оценка:
Здравствуйте, enji, Вы писали:

E>велосипедостроение потому что boost::signal напрямую использовать не получится — хочется фильтрацию и приоритеты вызовов. function кушает 16 байт и дает вызов по указателю на член + вызов виртуальной функции. Мои два указателя кушают 8 байт и дают простой вызов функции по указателю. Хотя конечно function значительно более удобен для оборачивания всяких лямбд. Может быть и перееду в конце концов на него.


Если источники сигнала всегда приходят типизированными, и только внутри твоей библиотеки заворачиваются в void*, то можно всегда брать их внутрь шаблонным методом/конструктором и класть рядом с void* указатель на шаблонную реализацию интерфейса, через котрый можно всё разрулить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.