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

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

Крестопроблемы отсутствия общего предка в иерархии, да?
Re[2]: Проверить тип void*
От: Abyx Россия  
Дата: 03.01.14 12:36
Оценка:
Здравствуйте, TarasB, Вы писали:

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


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

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

конечно если у тебя бесконечная память, ты можешь позволить себе пихать указатель на vptr+RTTI в каждый объект
только как производительностью запахнет — так сразу С да С++
In Zen We Trust
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[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: Проверить тип void*
От: zverjuga Беларусь  
Дата: 03.01.14 16:13
Оценка: -2
dynamic_cast ?
проклятый антисутенерский закон
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: Проверить тип void*
От: Vamp Россия  
Дата: 03.01.14 16:38
Оценка: +5
Нет способа. И незачем.
Да здравствует мыло душистое и веревка пушистая.
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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.