информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Все любят медПортрет посетителяСетевые кракеры и правда о деле Левина
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Microsoft обещает радикально усилить... 
 Ядро Linux избавляется от российских... 
 20 лет Ubuntu 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / beginners
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Господа, будьте снисходительны, не бросайтесь сразу штрафовать за, как вам кажется, глупые вопросы - beginners на то и beginners.
Вообще-то dynamic_cast от указателя возвращает нулевой указатель, а не швыряет исключение. 09.12.04 16:34  Число просмотров: 2508
Автор: Ktirf <Æ Rusakov> Статус: Elderman
<"чистая" ссылка>
<beginners>
заморочка с dynamic_cast 09.12.04 15:11  
Автор: zelych Статус: Member
<"чистая" ссылка>
решил тут, как-то попользовать dynamic_cast (не слишком я люблю rtti, но тут вот приспичило)..

как написано в msdn`е, если dynamic_cast не может преобразовать указатель к нужному типу генерируется исключение bad_cast, а если объект по указателю вообще не содержит rtti информации, то генерируется исключение __non_rtti_object..
ну а мне как-раз этого-то и надо.. хотел отделять мусорные указатели от настоящих..

не получилось..
вот небольшой исходничек:

#include <stdio.h>

class A {
int x;
public:
A(){ x = 0; }
int fun() { return x; }
};

class B : public A {
public:
B() { y = 1; }
int y;
};

void* get_ptr() { return */(void-1 /*/ new B/**/; }

void main()
{
A *x, *y = (A*) get_ptr();

try {
x = dynamic_cast<A*>( y );
} catch(...){
x = 0;
}

if( x ) printf( "%i", x->fun() );
}

вроде правильно, и rtti в свойствах проекта включил, только вот компилятор почему-то генерирует такой вот код (в release конфигурации):

void main()
{
A *x, *y = (A*) get_ptr();
try {
x = dynamic_cast<A*>( y );

00401000 or eax,0FFFFFFFFh

} catch(...){ x = 0; }

if( x ) printf( "%i", x->fun() );

00401003 mov eax,dword ptr [eax]
00401005 push eax
00401006 push offset string "%i" (4060FCh)
0040100B call printf (401016h)

получается, что на весь RUN-TIME в rtti ему пофигу..

просвятите, пожалуйста, откуда трабл такой..
Вообще-то dynamic_cast от указателя возвращает нулевой указатель, а не швыряет исключение. 09.12.04 16:34  
Автор: Ktirf <Æ Rusakov> Статус: Elderman
<"чистая" ссылка>
по поводу исключений - вычитано в msdn`е, да и нулевой указатель он не возвращает (хотя, судя по тому же msdn`у - должен) 09.12.04 16:43  
Автор: zelych Статус: Member
<"чистая" ссылка>
Ну что сказать - безобразие, что не возвращает... 10.12.04 14:04  
Автор: Ktirf <Æ Rusakov> Статус: Elderman
<"чистая" ссылка>
В целом по использованию приведений типа см. цитату amirul'а из Страуструпа. А надежного способа определения мусорных указателей в C++, увы, нет и не предвидится.
Универсального способа определения мусорного указателя вообще не существует, имхо (update) 10.12.04 15:24  
Автор: amirul <Serge> Статус: The Elderman
Отредактировано 10.12.04 15:34  Количество правок: 3
<"чистая" ссылка>
> В целом по использованию приведений типа см. цитату
> amirul'а из Страуструпа. А надежного способа определения
> мусорных указателей в C++, увы, нет и не предвидится.
Вернее можно внедрить в язык то, что можно сделать средствами C++ уже сейчас. Речь о том, чтобы сделать ВСЕ классы своей иерархии наследниками одного базового, например CObject

Ну и после этого делать что то типа:

class CObject {
private:
	static const unsigned long ExpectedSignature = 0x12345678; // Какое нить достаточно случайное число
	unsigned long Signature;

public:
	CObject(): Signature(ExpectedSignature) {}
	virtual ~CObject() = 0;

	bool IsObject() {
		__try {
			return (Signature == ExpectedSignature);
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return false;
		}
	}
};

---

ну и использовать как нибудь так:

void
f(void *ptr) {
	CObject *object = reinterpret_cast<CObject *>(ptr);

	if (object->IsObject()) {
		deriv = dynamic_cast<CMyDerivedClass *>(object);
	} else {
		throw bad_cast();
	}
}

---

Вероятность того, что под этим указателем будет память и при этом будет содержать нужную сигнатуру будет меньше, чем 2^(-32)

Хотя эта самая сигнатура является ничем иным как полем типа, которое в C++ не рекомендуется. Опять таки повторюсь, что не знаю ни одной ситуации, которая бы привела к ПОЛНОЙ потере информации о типе в C++. Скорее всего дизайн проекта сделан не совсем верно. Если скажут, какую задачу нужно решить с помощью динамического кастования, то возможно мы найдем другой способ

-----------------
В вышеприведенном коде вместо микрософтовского SEH вполне можно использовать стандартные try/catch блоки
Для использования RTTI класс должен быть абстрактным 09.12.04 15:42  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> class A {
> int x;
> public:
> A(){ x = 0; }
> int fun() { return x; }
> };
>
> class B : public A {
> public:
> B() { y = 1; }
> int y;
> };
То бишь иметь виртуальные функции.


> просвятите, пожалуйста, откуда трабл такой..
А вообще использование RTTI чаще всего говорит о плохой архитектуре проекта. Лучше пересмотри, мож чего можно сделать с помощью обычных виртуальных функций и статической типизации
Неправда твоя. 09.12.04 16:29  
Автор: Ktirf <Æ Rusakov> Статус: Elderman
<"чистая" ссылка>
Для использования RTTI необходимо и достаточно включить флажок у компилятора.
Ладно, мож это устаревшая информация 09.12.04 16:37  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Для использования RTTI необходимо и достаточно включить
> флажок у компилятора.
Как доберусь до страуструпа - скажу точнее. Но я точно помню, что он писал про то, что инфа для RTTI хранится в vtbl-е, а vtbl создается если есть виртуальные функции. Мож это расширение от микрософта, а мож я чего-й-то гоню. Надо проверить
Добрался до страуструпа 10.12.04 12:50  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
Итак

1. Для кастинга, который можно сделать обычным static_cast-ом (от дочернего класса к базовому) поведение dynamic_cast-а совпадает со статическим.

2. Для downcasting-а (вниз по иерархии, то бишь от базового к наследнику) необходимо чтобы кастуемая переменная (а не тип в который она кастуется) имела полиморфный (перед этим я ошибочно назвал его абстрактным) тип. То бишь иметь виртуальные функции.
То есть, если хочется сделать
dynamic_cast<T *>(ptr);
То ptr - ОБЯЗАТЕЛЬНО должен иметь полиморфный тип, а T - может быть любым (в том числе и конкретным классом)

3. dynamic_cast к указателю в случае ошибки всегда возвращает NULL. Исключения бросает кастинг к ссылке:
dynamic_cast<T &>(var);
в случае когда такое приведение невозможно (во всех случаях когда вернулся бы указатель NULL)

Теперь замечания. Я не могу придумать ни одного случая, когда в C++ полностью теряется информация о типе (то бишь об указателе известно только то, что он void *). Вообще в C++ не так уж часто применяется (void *)
спасибо, теперь вроде ясно.. 10.12.04 18:02  
Автор: zelych Статус: Member
<"чистая" ссылка>
> 1. Для кастинга, который можно сделать обычным
> static_cast-ом (от дочернего класса к базовому) поведение
> dynamic_cast-а совпадает со статическим.

похоже, именно это и происходит..

> Теперь замечания. Я не могу придумать ни одного случая,
> когда в C++ полностью теряется информация о типе (то бишь
> об указателе известно только то, что он void *). Вообще в
> C++ не так уж часто применяется (void *)

а я, вот, придумал..
трабл такой получается при объединении моих объектов с WinAPI..
И где именно ты теряешь тип? 10.12.04 18:57  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> а я, вот, придумал..
> трабл такой получается при объединении моих объектов с
> WinAPI..
Не верю :-)
Сам неоднократно швырял указатели в WinAPI. Но при этом точно знал, что как минимум на какой-то базовый объект данный указатель указывает. Уточни задачу - мож чего и придумаем
CreateWindow -> CBT Hook 14.12.04 16:54  
Автор: zelych Статус: Member
<"чистая" ссылка>

> Сам неоднократно швырял указатели в WinAPI. Но при этом
> точно знал, что как минимум на какой-то базовый объект
> данный указатель указывает. Уточни задачу - мож чего и
> придумаем

В CreateWindow последним аргументом кладу указатель на некоторый объект, который будет ассоциироваться с окном..
При этом, хуком отлавливаю все создания окон и заношу в списочек hwnd окна и через CBT_CREATEWND вытаскиваю lpParam - последний аргумент CreateWindow..
Естественно, пару лишних движений мышкой - и винда насоздаёт кучу окошек, у которых lpParam указыавет на какую-то хрень..

вот их-то и надо отсеять..
такие дела..


и ещё до кучи.. что бы немного отвлечься..
В msdn`е написано:
"Bitmaps as Brushes
A number of functions use the brush currently selected into a device context to perform bitmap operations. For example, the PatBlt function replicates the brush in a rectangular region within a window, and the FloodFill function replicates the brush inside an area in a window bounded by the specified color (unlike PatBlt, FloodFill does fill nonrectangular shapes). "

получается что можно использовать картинку в качестве кисточки, хотело поробовать, но не получилось.. никак не ругается, но вместо картинок просто белым цветом закрашивает..
Ну тогда наверное сигнатурку надо, как выше показано 14.12.04 17:58  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> получается что можно использовать картинку в качестве
> кисточки, хотело поробовать, но не получилось.. никак не
> ругается, но вместо картинок просто белым цветом
> закрашивает..
Я с GDI не слишком, но сделал ли ты SelectObject перед рисованием.
С этим делом разобрался.. 15.12.04 12:16  
Автор: zelych Статус: Member
<"чистая" ссылка>
причём совершенно мистическим способом:
сегодня утром решил ещё раз посмотреть хелп.. вместо раздела Bitmaps открываю Brushes->Brush Functions и обнаруживаю там CreatePatternBrush..
не катит [upd] 09.12.04 16:03  
Автор: zelych Статус: Member
Отредактировано 09.12.04 16:10  Количество правок: 1
<"чистая" ссылка>
> То бишь иметь виртуальные функции.

class A {
int x;
public:
A(){ x = 0; }
virtual int fun() { return x; }
};

class B : public A {
public:
B() { y = 1; }
int y;
virtual int fun() { return y; }
};

вроде как, теперь есть..
компилятор генерирует точно такой же код (один в один)..
похоже, что компилятор считает себя очень умным, и решил run-time не использовать..

> А вообще использование RTTI чаще всего говорит о плохой
> архитектуре проекта. Лучше пересмотри, мож чего можно
> сделать с помощью обычных виртуальных функций и статической
> типизации

ну, наверное, не зря он есть..
а если без него, то как?? всё что приходит мне в голову, можно рассматривать как собственную реализацию rtti.. иначе придумать не умею..


[upd] PS имхо, абстрактные - классы у которых не все функции реализованы.. и в с++ их делать нельзя..
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach