LINUX.ORG.RU

[g++] dynamic_cast возвращает 0x4, а не 0 — неужели баг?

 


0

0

Это баг или может нужны опции компилятору?

5.2.7.9 драфта на с++0х:

The value of a failed cast to pointer type is the null pointer value of the required result type.

http://www.kuzbass.ru:8086/docs/isocpp/expr.htm

The value of a failed cast to pointer type is the null pointer value of the required result type.


$ cat test1.cxx

#include <iostream>

#define AS(T) as<T>()

template<typename T> class Boxed;

class Something
{      
public:
  virtual void print_value_size() {};
  template<typename T> T* as() { return (dynamic_cast<Boxed<T>*>(this))->get(); }
  virtual ~Something(){} 
};

template<typename T> class Boxed: public Something
{
private:
  T value;
public:
  Boxed<T>(T arg): value(arg) {}
  T* get() { return &value; }
  virtual void print_value_size() { std::cout << " sizeof=" << sizeof(value); }
  virtual ~Boxed(){}
};

template<typename T> inline Boxed<T>* boxed(T arg) { return new Boxed<T>(arg); }

/// usage:
int main()
{
  Something* x[]={ boxed(1), boxed("asdf"), boxed(3.0) };
  for( int i=0; i<3; i++) {
    x[i]->print_value_size();
    int* y = x[i]->AS(int); 
    if( y!=NULL ) std::cout << " int=" << y << ' ';
    std::cout << '\n';
  }
}



$ g++ test1.cxx && ./a.out

 sizeof=4 int=0x804b00c 
 sizeof=4 int=0x4 
 sizeof=8 int=0x4 

Такая фигня на g++ Debian 4.3.2-1.1 и 4.1.2-21

d:/work $ ./test
 sizeof=4 int=0x3e2bdc 
 sizeof=4 int=0x4 
 sizeof=8 int=0x4 

d:/work $ g++ --version
g++.exe (GCC) 3.4.2 (mingw-special)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

yoghurt ★★★★★
()

Чего ты ожидаешь?
dynamic_cast вернул тебе 0, но ты же его не проверяешь, а get() возвращает тебе этот 0 + 4 (0 + смещение для value).
А ты ждал SEGV? Но здесь ведь ты его не ждал бы:
int *p = 0;
int *pp = p + 1;

sergio_nsk
()
Ответ на: комментарий от sergio_nsk

> А ты ждал SEGV

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

Т.е. в данном случае поймать вызов NULL->get().

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Если это не выдуманная проблема, то пожалуйста.

Возможность на практике убедиться, что не всегда this == &first_member.

sergio_nsk
()
Ответ на: комментарий от sergio_nsk

> Возможность на практике убедиться, что не всегда this == &first_member.

this в данном случае это очевидно указатель на vtbl

> Если это не выдуманная проблема, то пожалуйста.

?

Вот если я так же лоханусь в каком-нить сложном месте, хотелось бы сделать отладочный билд и поймать NULL->something(....)

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

> Тогда возникает другой вопрос -- есть ли отладочный режим (либа?)

Нет. Это простая процессорная арифметика. Правило простое: не откладывай проверку возвращаемого значения на потом, и не будет проблем. Простые примеры: errno в С/С++ или $? в sh/bash -- их значения могут затереться следующим вызовом.

Вот если бы было обращение к элементу, а не к его адресу, тогда бы словил "диагностику".

sergio_nsk
()

GCC 4.4.0
GCC 4.3.3
GCC 4.2.4
GCC 4.1.2
GCC 3.4.6

Intel C/C++ 10.1 и 11.0 cоответственно

~/tmp :$c++44 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804b00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$c++43 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804a00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$c++42 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804b00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$c++41 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804b00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$c++3 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804b00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$icpc10 test.cpp
~/tmp :$./a.out
sizeof=4 int=0x804d00c
sizeof=4 int=0x4
sizeof=8 int=0x4
~/tmp :$icpc11 test.cpp
~/tmp :$./a.out
Segmentation fault

Sylvia ★★★★★
()
Ответ на: комментарий от Sylvia

> Segmentation fault

Упс! Все остальные ведут себя понятно, а почему этот так???

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от sergio_nsk

> Правило простое: не откладывай проверку возвращаемого значения на потом, и не будет проблем.

Это *ЗДЕСЬ* оно простое, а если допустим сложная прога, я считаю что p всегда не ноль и так оно и есть *почти* всегда, вызываю функцию, которая фактически сам p не разыменовывает, потом результат уплывает дааалеко, и через часик результат 0х24 разыменовывается.

В этом смысле поведение ic11 мне больше нравится.

Да, внутри каждой нестатической функции можно поставить assert, но как-бы хотелось бы это делать, не захламляя код.

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от Sylvia

Silvy, воткни std::cout << std::endl; вместо std::cout << '\n'. так будет видно, что оно успевает вывести (std::endl сбрасывает буферы в объектах stream).

sergio_nsk
()
Ответ на: комментарий от www_linux_org_ru

> Это *ЗДЕСЬ* оно простое, а если допустим сложная прога

Вот это и есть выдуманная проблема. Ты ведь как-то это p получаешь, через аргумент или как результат некоторой функции/вычислений. Ну так проверяй полученный p сразу после его получения, до операций с его участием.

sergio_nsk
()
Ответ на: комментарий от sergio_nsk

> А ты ждал SEGV?

[ хотя это уход от интересной темы, но я имел в виду

template<typename T> T* as() {
Boxed<T>* p=dynamic_cast<Boxed<T>*>(this);
return p?p->get():NULL;
}

-- гораздо интереснее, когда не ожидаешь null от dynamic_cast ]

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от sergio_nsk

> Вот это и есть выдуманная проблема. Ты ведь как-то это p получаешь, через аргумент или как результат некоторой функции/вычислений. Ну так проверяй полученный p сразу после его получения, до операций с его участием.

Это *здесь* она выдуманная. На самом деле я случай с NULL предварительно обдумал, из-за него специально выбрал указатель вместо ссылки (ссылка генерит эксепшн, а мне хотелось передать 0 дальше), а потом вдруг вот так криво записал.

Но ведь может случиться и по-другому. И может оказаться не выдуманной.

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от sergio_nsk

> Вот это и есть выдуманная проблема.

Можно забыть про источник проблемы, и просто спросить "как в каждой нестатической функции класса проверять this на не NULL и не захламлять код кучей ассертов?"

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от Sylvia

> GCC 4.4.0
> GCC 4.3.3
> GCC 4.2.4
> GCC 4.1.2
> GCC 3.4.6

> Intel C/C++ 10.1 и 11.0 cоответственно

Маньяка! Зачем тебе столько компиляторов?..

Хм....

for i in sbcl clisp cmucl ccl gcl ecl scl allegro lispworks; do
    cl-launch --lisp $i -ip '(format nil "~a ~a~%" (lisp-implementation-type) (lisp-implementation-version))'
done

SBCL 1.0.28.8

CLISP 2.47 (2008-10-23) (built on x86-7.fedora.phx.redhat.com)

CMU Common Lisp 19f (19F)

Clozure Common Lisp Version 1.2-r10552  (LinuxX8664)

GNU Common Lisp (GCL) GCL 2.6.8

ECL 0.9l (CVS 2008-06-19 17:09)

Scieneer Common Lisp 1.3.9

International Allegro CL Free Express Edition 8.1 [Linux (x86)] (Jun 29, 2008 13:34)

LispWorks Personal Edition 5.1.1

mv ★★★★★
()

мдя, так не пробовали написать?

class Something
{
public:
virtual void print_value_size() {};
template<typename T> T* as()
{
typedef Boxed<T>* pointer_type;
pointer_type p = dynamic_cast<pointer_type>(this);
if(p != 0)
{
return p->get();
}
return 0;
}
virtual ~Something(){}
};

acefsm
()
Ответ на: комментарий от www_linux_org_ru

Вызов невиртаульного метода в контексте 0-го this допустим

namezys ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.