Deep C++. Operation: static_cast. Перевод - Igor Sukharev
От: Аноним Robert Schmidt  
Дата: 20.06.03 16:21
Оценка: 281 (9) +1
Статья :
Deep C++. Operation: static_cast
Автор(ы): Robert Schmidt
Дата: 30.09.2002


Авторы :
Robert Schmidt

Аннотация :
Как подсказывает название, static_cast преобразует выражения одного статического типа в объекты и значения другого статического типа.
Re: Deep C++. Operation: static_cast. Перевод - Igor Sukhare
От: Андрей Тарасевич Беларусь  
Дата: 20.06.03 17:06
Оценка: 27 (3) +1
Здравствуйте, Аноним, Вы писали:

А>Как подсказывает название, static_cast преобразует выражения одного статического типа в объекты и значения другого статического типа.


В статье есть очевидная ошибка при описании преобразований указателей на члены класса.

Во-первых, преобразование 'Base::*' -> 'Derived::*' (при условии, что классы 'Base' и 'Derived' являются соответственно предком и потомком) является стандартным преобразованием и никакого явного каста не требует. "Обратным" преобразованием к этому преобразованию будет преобразование 'Derived::*' -> 'Base::*', которое как раз таки и выполняется при помощи 'static_cast'. Ситуация с указателями на члены в точности обратна (симметрична) ситуации с указателями на объекты: указатели на объекты — covariance, указтели на члены — contravariance.

Во-вторых, утверждение о том, что приведение 'Base::*' -> 'Derived::*' приводит к неопределенному поведению, если исходный указатель не указывет на член класса 'Derived', совешенно не верно. Ни стандартное приведение 'Base::*' -> 'Derived::*', ни приведение 'Derived::*' -> 'Base::*', выполняемое при помощи 'static_cast' никогда не приводят к неопределенному поведению (при условии, что классы 'Base' и 'Derived' являются соответственно предком и потомком). Неопределенное поведение может возникнуть на этапе разадресации указателя на отсутствующий член класса, но не на этапе приведения типа.
Best regards,
Андрей Тарасевич
Re[2]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: Masterkent  
Дата: 01.04.09 09:55
Оценка: 5 (2) +1
Здравствуйте, SergioSV, Вы писали:

SSV>Исходя из статьи можно предположить то, что любой тип можно избавить от cv-модификаторов с использованием одного лишь static_cast


Избавить-то можно, но ценой undefined behavior:

const volatile int t0 = 5;
const volatile int *t1 = &t0;
int *t2 = *static_cast<int **>(static_cast<void *>(&t1));
int &t3 = *t2;

Формально такая цепочка преобразований не подпадает под правило во втором предложении 5.2.9/10:

A value of type pointer to object converted to “pointer to cv void” and back to the original pointer type will have its original value

а значит, это подпадает под второе предложение 1.3.12:

Undefined behavior may also be expected when this International Standard omits the description of any explicit definition of behavior.

Также не следует забывать про 7.1.5.1/7:

If an attempt is made to refer to an object defined with a volatile-qualified type through the use of an lvalue with a non-volatile-qualified type, the program behaviour is undefined

Re: Deep C++. Operation: static_cast. Перевод - Igor Sukhare
От: SergioSV Россия  
Дата: 01.04.09 09:06
Оценка:
Здравствуйте, Robert Schmidt, Вы писали:

RS>Статья :

RS>Deep C++. Operation: static_cast
Автор(ы): Robert Schmidt
Дата: 30.09.2002


RS>Авторы :

RS>Robert Schmidt

RS>Аннотация :

RS>Как подсказывает название, static_cast преобразует выражения одного статического типа в объекты и значения другого статического типа.

Исходя из статьи можно предположить то, что любой тип можно избавить от cv-модификаторов с оспользованием одного лишь static_cast'а, в результате я попробовал скомпилировать следующий код:

const volatile int t0 = 5;
const volatile void* t1 = static_cast<const volatile void*>(&t0);
int* t2 = static_cast<int*>(t1); // ошибка преобразования типа
int& t3 = *t2;


Использовал следующие компиляторы: MSVS 2008 (v9 которая), comeau (Comeau C++ Online)
Re[3]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: SergioSV Россия  
Дата: 01.04.09 11:17
Оценка:
Здравствуйте, Masterkent, Вы писали:

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


SSV>>Исходя из статьи можно предположить то, что любой тип можно избавить от cv-модификаторов с использованием одного лишь static_cast


M>Избавить-то можно, но ценой undefined behavior:


С этим вопросом вроде разобрался:

1. Исходя из стандарта 98-года получаем (5.2.9/10):

An rvalue of type "pointer to cv void" can be explicitly converted to a pointer to object type. A value of type pointer to object converted to “pointer to cv void” and back to the original pointer type will have its original value.


Т.е., выходит, что преобразование "(возможно cv-квалифицированный) void * в любой T *" не запрещено.

2. Исходя из Working Draft, Standard for Programming Language C++ (2005-10-19), получаем (5.2.9/11):

An rvalue of type “pointer to cv1 void” can be converted to an rvalue of type “pointer to cv2 T,” where T is an object type
and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. A value of type pointer to object converted
to “pointer to cv void” and back, possibly with different cv-qualification, shall have its original value. [ Example:
T* p1 = new T;
const T* p2 = static_cast < const T*>( static_cast < void *>( p1 ));
bool b = p1 == p2 ; / / b will have the value true.
—end example ]


Т.е., преобразование "(возможно cv-квалифицированный) void * в любой T *" разрешено, но с оговорками:

An rvalue of type “pointer to cv1 void” can be converted to an rvalue of type “pointer to cv2 T,” where T is an object type
and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.

Re[3]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: SergioSV Россия  
Дата: 01.04.09 11:30
Оценка:
Здравствуйте, Masterkent:

На мой взгляд, в статье не хватает привязки к конкретному стандарту.
Re[2]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: Vain Россия google.ru
Дата: 01.04.09 11:50
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Во-первых, преобразование 'Base::*' -> 'Derived::*'

Это приобразование от базы или к базе?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: Deep C++. Operation: static_cast. Перевод - Igor Sukhare
От: Vain Россия google.ru
Дата: 01.04.09 11:53
Оценка:
Здравствуйте, Robert Schmidt, Вы писали:

RS>Статья :

RS>Deep C++. Operation: static_cast
Автор(ы): Robert Schmidt
Дата: 30.09.2002

Исходя из статьи это должно компилироваться:
float const f = 0;
int main()
{
  static_cast<int const*>(&f);
  return 0;
}

Действительно ли?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[4]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: Masterkent  
Дата: 01.04.09 12:49
Оценка:
Здравствуйте, SergioSV, Вы писали:

SSV>1. Исходя из стандарта 98-года получаем (5.2.9/10):


В настоящий момент действующим стандартом C++ является ISO/IEC 14882:2003(E) aka C++03, а стандарт 98-го года недействителен:

ISO/IEC 14882:2003(E) / Foreword

This second edition cancels and replaces the first edition (ISO/IEC 14882:1998), which has been technically revised.

В C++03 данное преобразование описывается так:

5.2.9/10

An rvalue of type “pointer to cv1 void” can be converted to an rvalue of type “pointer to cv2 T,” where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. A value of type pointer to object converted to “pointer to cv void” and back to the original pointer type will have its original value.

Re[2]: Deep C++. Operation: static_cast. Перевод - Igor Sukh
От: Masterkent  
Дата: 01.04.09 13:03
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, Robert Schmidt, Вы писали:


Насколько я понимаю, это всего лишь перевод статьи, и касаемо данного ляпа специально сделана ремарка:

(С точки зрения стандарта, эти примеры недопустимы: static_cast не может приводить указатели несвязанных типов, каковыми являются int и float — прим. RSDN.)

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.