Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Сентябрь 18, 2012, 12:44



Название: Достоинства static_cast
Отправлено: Igors от Сентябрь 18, 2012, 12:44
Добрый день

Навеяно этим
Поэтому в C++ специально сделали безопасный статик_каст, а за C style cast надо по рукам бить. Сколько я уже наслышался проблем из-за него.
Хочу услышать. Всем понятно что static_cast - это как бы "показатель грамотности", и я с этим полностью согласен. Однако можете ли Вы привести примеры (и побольше) где static_cast работает корректно, а вот С приведение - нет? Я лично затрудняюсь

Спасибо


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 18, 2012, 13:06
Допустим, С каст игнорирует константность.

const char *const a = new char;
int *b = static_cast <int*> (a); - ошибка
int *c = (int*) (a); - все нормально


Название: Re: Достоинства static_cast
Отправлено: CuteBunny от Сентябрь 18, 2012, 16:44
Мой пример:

Код
C++ (Qt)
#include <iostream>
 
class A
{
};
 
class B : public A
{
};
 
class C
{
};
 
int main()
{
   B b;
   C c;
   A *pA = 0;
   pA = (A*)&c; //it's ok for compiler
   pA = static_cast<A*>(&c); //it's bad for compiler... well except for the one i got
}
 

Как мне видется нужность static_cast в том, что он проверяет на стадии компиляции является ли объект А объектом Б, т.е. банально проверяется отношение is-a, если А не есть Б, то такое преобразование ошибочно... Поправьте, если ошибаюсь, я еще всё еще чайник:)


Название: Re: Достоинства static_cast
Отправлено: xokc от Сентябрь 18, 2012, 21:40
Всем понятно что static_cast - это как бы "показатель грамотности", и я с этим полностью согласен.
А вот я с этим совершенно не согласен. Если человек понимает отличие "cast" друг-от друга, то ему никогда этот самый static_cast и не понадобится. Использование"cast" как табу и показателя грамотности - есть абсолютное зло, в стиле "я не знаю ПОЧЕМУ теперь принято в инкременте цикла использовать ++i, а не i++, но (на всякий случай) пишу именно так, поскольку это - "показатель грамотности".


Название: Re: Достоинства static_cast
Отправлено: Akon от Сентябрь 18, 2012, 22:19
+CuteBunny
Основное достоинство в том, что static_cast не "опускается" до reinterpreta, в то время как С-стайл запросто.

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


Название: Re: Достоинства static_cast
Отправлено: LisandreL от Сентябрь 18, 2012, 23:42
Основное достоинство в том, что static_cast не "опускается" до reinterpreta, в то время как С-стайл запросто.
reinterpret - это ещё не вся глубина падения. С-стайл каст делает ещё и const_cast.
И если у reinterpret'а  я запросто могу придумать разумные применения ( ну, например добавление данных при через QByteArray::append ( const char * str, int len ) ), то если вам понадобился const_cast, то почти наверняка у вас (или у используемой вами библиотеки) что-то не так с кодом.

Ну а так по кастам: dynamic_cast и qobject_cast - могут использоваться для проверки типа объекта, если он точно неизвестен.
Static, reinterept и const касты генерируют ошибку времени и в общем-то просто могут уберечь от ошибки в коде.


Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 19, 2012, 07:10
+CuteBunny
Основное достоинство в том, что static_cast не "опускается" до reinterpreta, в то время как С-стайл запросто.

Цитировать
Что делает приведение типов в стиле С: пытается использовать static_cast, если не получается, использует reinterpret_cast. Далее, если нужно, использует const_cast .
Приведение типов в C++ (http://alenacpp.blogspot.com/2005/08/c.html)

Цитировать
если вам понадобился const_cast, то почти наверняка у вас (или у используемой вами библиотеки) что-то не так с кодом.
Значит с STL что-то не так, т. к. у std::map нет константного operator[].


Название: Re: Достоинства static_cast
Отправлено: Akon от Сентябрь 19, 2012, 09:04
Цитировать
reinterpret - это ещё не вся глубина падения. С-стайл каст делает ещё и const_cast.
Да, защита от потери константности тоже большое дело.

Цитировать
то если вам понадобился const_cast, то почти наверняка у вас (или у используемой вами библиотеки) что-то не так с кодом
Правильно.

Цитировать
Значит с STL что-то не так, т. к. у std::map нет константного operator[].
У него семантика такая. Для конст. мапа и поиска есть std::map::find().


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 19, 2012, 09:32
Значит с STL что-то не так, т. к. у std::map нет константного operator[].

В новом стандарте есть:
const T & at( const Key& key ) const; (since C++11)


Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 19, 2012, 09:54
В новом стандарте есть:
const T & at( const Key& key ) const; (since C++11)
1. Не все компиляторы поддерживают C++11;
2. Не все компиляторы поддерживают стандартные исключения.


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 19, 2012, 10:01
1. Большинство уже поддерживает.
2. Всегда есть std::map::find, как уже сказали выше.


Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 19, 2012, 10:06
У него семантика такая. Для конст. мапа и поиска есть std::map::find().
find() возвращает итератор, который в случае отсутствия элемента будет container.end();
Проверить наличие элемента в мапе я могу простым count, а вот получить значение через operator[] не могу.
На лицо явная проблема с удобством использования.

Бывают такие структуры данных, которые используют частотные характеристики данных, и меняют свое состояние от каждого запроса на поиск, в этом случае что?
 Запилим mutable и константые методы?


Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 19, 2012, 10:09
1. Большинство уже поддерживает.
gcc-3X не поддерживает, да и сам стандарт не полностью поддерживается компиляторами. Это все привязка к компиляторам и реализациям STL, которую лучше избегать если нужна кроссплатформенность.


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 19, 2012, 10:21
1. Большинство уже поддерживает.
gcc-3X не поддерживает, да и сам стандарт не полностью поддерживается компиляторами. Это все привязка к компиляторам и реализациям STL, которую лучше избегать если нужна кроссплатформенность.

А Qt4 разве собирается с gcc-3Х? Если так завязываться за старое, никакого прогресса не будет.


Название: Re: Достоинства static_cast
Отправлено: LisandreL от Сентябрь 19, 2012, 11:11
А Qt4 разве собирается с gcc-3Х?
4.5 собиралось. http://www.prog.org.ru/topic_12303_0.html

Значит с STL что-то не так, т. к. у std::map нет константного operator[].
Ну если б с ней было всё так, её б не меняли с приходом нового стандарта.

Проверить наличие элемента в мапе я могу простым count, а вот получить значение через operator[] не могу.
Код
C++ (Qt)
map.find( x )->second

Бывают такие структуры данных, которые используют частотные характеристики данных, и меняют свое состояние от каждого запроса на поиск, в этом случае что?
 Запилим mutable и константые методы?
Ну, если они меняются, то константой они быть не могут (с точки зрения логики, а не возможностей языка).
Хотя ваш вариант сработает.


Название: Re: Достоинства static_cast
Отправлено: Igors от Сентябрь 19, 2012, 11:45
Попробуем подытожить чем лучше static_cast

- не позволяет (на этапе компиляции) привести типы которые не могут быть совместимы
- соблюдает константность

Хмм... пока больше ничего по существу не слышал :) От себя добавлю

- исключает возможность перепутать с перекрытым оператором (напр char*)
- хорошо заметен в коде (по-моему главное)

Смущает однако почти полное отсутствие примеров, да и имеющиеся не очень убедительны
Код
C++ (Qt)
QWidget * w;
..
QLineEdit * e = static_cast <QLineEdit *> (w);
 
Сравнивая это с топорным (QLineEdit *) w, - там мы падаем с 9-го этажа, а тут с 7-го. Да, наши шансы на выживание повышаются, но так ли уж значительно?  :)

По поводу "ах, потеряли константность - как низко мы пали!" и.т.п. Давайте я создам др тему? По константности есть что обсудить - и много, но мешать все в кучу нехорошо


Название: Re: Достоинства static_cast
Отправлено: lesav от Сентябрь 19, 2012, 12:16
Падая с этажа можно и парашют прихватить
Код
C++ (Qt)
QWidget * w;
QLineEdit * e = static_cast <QLineEdit *> (w);
if (e)
{
 // OK
}
 


Название: Re: Достоинства static_cast
Отправлено: lesav от Сентябрь 19, 2012, 12:29
Пардон, static_cast в таком случае бесполезен.
Условие срабатывает только с dynamic_cast


Название: Re: Достоинства static_cast
Отправлено: Bepec от Сентябрь 19, 2012, 12:56
Помоему все касты - есть лишь:

1) заметность в коде
2) ясность чего хотел пишущий эту строку программист
3) в последнюю очередь это проверки :)

PS для меня удобнее будет увидеть статик каст и понять, что могут поступить неверные данные, чем смотреть на одинаковые (QLineEdit *) :)


Название: Re: Достоинства static_cast
Отправлено: Igors от Сентябрь 19, 2012, 13:18
Ну хорошо, а вот примерчик (видел у Вити которого что-то пока не видно - занят наверно)
Код
C++ (Qt)
double d;
float f;
,,,
d = static_cast <double> (f);
f = static_cast <float> (d);
 
Понятно "дело вкуса", но все же - уместно ли такое использование static_cast? Является ли оно "хорошим тоном" или так - понты?


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 19, 2012, 13:30
Скорее тогда уже не "дело вкуса", а придерживание единого стиля. Что значит не так уж мало.


Название: Re: Достоинства static_cast
Отправлено: Akon от Сентябрь 19, 2012, 13:54
Код:
QWidget * w;
..
QLineEdit * e = static_cast <QLineEdit *> (w);
В таких случаях нужно использовать boost::boost_polymorphic_dowcast или qpolymorphic_dowcast и падать только в дебаге.

Код:
d = static_cast <double> (f);
f = static_cast <float> (d);
ОК, придерживаясь стиля
Код:
int i = 0x11223344;
char c = static_cast<char>(i);
Ну а теперь я меняю char c на short c и обламывась со вторым байтом (если не пофиксю все присваивания в коде).


Название: Re: Достоинства static_cast
Отправлено: Bepec от Сентябрь 19, 2012, 13:58
Тащить boost в Qt-шный проект это конечно же хорошо :)
И да, вы обламываетесь потому, что так написали :)


Название: Re: Достоинства static_cast
Отправлено: LisandreL от Сентябрь 19, 2012, 13:59
Сравнивая это с топорным (QLineEdit *) w, - там мы падаем с 9-го этажа, а тут с 7-го.
Незначительно, но и стоит это нам только несколько дополнительных набранных символов. Проверки происходят на этапе компиляции, так что в производительности мы не потеряем (хотя и это не всегда критично).

Условие срабатывает только с dynamic_cast
С незанулённым указателем не сработает.


Название: Re: Достоинства static_cast
Отправлено: Igors от Сентябрь 19, 2012, 14:14
Скорее тогда уже не "дело вкуса", а придерживание единого стиля. Что значит не так уж мало.
То есть это правильно, хорошо? Тогда прошу показать как написать напр такой кусочек (максимально упрощенный) в хорошем стиле приведения

Код
C++ (Qt)
struct Matrix2x2 {
double m00, m01, m10, m11;
};
 
void Transform( const Matrix2x2 & m, float * ioX, float * ioY )
{
double x = *ioX;
double y = *ioX;
 
*ioX = x * m.m00 + y * m.m10;
*ioY = x * m.m10 + y * m.m11;
}
 


Название: Re: Достоинства static_cast
Отправлено: CuteBunny от Сентябрь 19, 2012, 15:35
Ну хорошо, а вот примерчик (видел у Вити которого что-то пока не видно - занят наверно)
Код
C++ (Qt)
double d;
float f;
,,,
d = static_cast <double> (f);
f = static_cast <float> (d);
 
Понятно "дело вкуса", но все же - уместно ли такое использование static_cast? Является ли оно "хорошим тоном" или так - понты?

Мне кажется:
Код
C++ (Qt)
d = static_cast<double>(f);
 
бессмысленная запись, т.к. d = f - ничего страшного не будет и по стандарту написано, что float to double conversion is safe, float же меньше double и поэтому никаких потерей точностей не будет...
Код
C++ (Qt)
f = static_cast <float> (d);
 

здесь да дело вкуса, можно static_cast<float>, можно (float) - в принципе оно быстрее по написанию...


Название: Re: Достоинства static_cast
Отправлено: CuteBunny от Сентябрь 19, 2012, 15:55
Скорее тогда уже не "дело вкуса", а придерживание единого стиля. Что значит не так уж мало.
То есть это правильно, хорошо? Тогда прошу показать как написать напр такой кусочек (максимально упрощенный) в хорошем стиле приведения

Код
C++ (Qt)
struct Matrix2x2 {
double m00, m01, m10, m11;
};
 
void Transform( const Matrix2x2 & m, float * ioX, float * ioY )
{
double x = *ioX;
double y = *ioX;
 
*ioX = x * m.m00 + y * m.m10;
*ioY = x * m.m10 + y * m.m11;
}
 


Думается мне это таким образом:

Если напишу так:

Код
C++ (Qt)
struct Matrix2x2 {
double m00, m01, m10, m11;
};
 
void Transform( const Matrix2x2 & m, float * ioX, float * ioY )
{
double x = *ioX;
double y = *ioX;
 //IMHO: there's no difference in this situation whether I'll write explicit conversion in c++ style or in c-style
 //however i know few about c language, so I'd prefer to do everything in c++ way rather than in c-way
*ioX = static_cast<float>(x * m.m00 + y * m.m10); //or in C-style (float)(x * m.m00 + y * m.m10)
*ioY = static_cast<float>(x * m.m10 + y * m.m11); //or in C-style (float)(x * m.m00 + y * m.m10)
}
 


значи я знаю, что у меня никогда не будет потерей точностей и говорю это компилятору, чтобы не сыпал варнинг... Хотя мне кажется тут на лицо, опасность, т.к. double'ы умножаются потом еще и складываются, когда-нибудь выстрел будет в ногу... поэтому если я не уверен, что (x * m.m00 + y * m.m10) и (x * m.m10 + y * m.m11) - поместится во float, я вообще не буду писать никаких приведениев ни в С++ стиле ни в Си, оставлю так, пусть компилятор говорит мне об потенциальной опасности в будущем...


Название: Re: Достоинства static_cast
Отправлено: V1KT0P от Сентябрь 19, 2012, 20:53
Ну хорошо, а вот примерчик (видел у Вити которого что-то пока не видно - занят наверно)
Понятно "дело вкуса", но все же - уместно ли такое использование static_cast? Является ли оно "хорошим тоном" или так - понты?
Тут уже сказали основное. У меня привычка кастить примитивные типы появилась после того, как без каста код который вроде как должен нормально работать работал не так как надо(если очень интересно, то я могу попробовать порыться в старых исходниках и найти участок где отсутствие каста приводит к неправильному поведению). Также каст примитивных типов служит явным выделением участка кода к которому надо присмотреться, может там затаилась ошибка.
Также статик использую для явного приведения к базовому классу.
Динамик каст использую для привидения к наследнику, а также он спасает от ошибок(попытка привести к классу которым он не является).
Констант и реинтерпрет касты использую только в исключительных ситуациях, ибо если она появляется то ошибка в архитектуре и надо ее менять.


Название: Re: Достоинства static_cast
Отправлено: Пантер от Сентябрь 19, 2012, 21:52
констант_каст я юзаю при работе со сторонними либами с плохим апи или для снятия конста с this в константных методах. Что одно, что другое бывает достаточно редко.
реинтерпрет_каст я юзаю для чтения сишных структур из блока данных.


Название: Re: Достоинства static_cast
Отправлено: Akon от Сентябрь 19, 2012, 22:24
А вот такая конструкция присуща адептам const propagation (в коих числюсь и я):
Код:
class ControlUnit {
...
const QList<Terminal*>& terminals() { return terminals_; }
const QList<const Terminal*>& terminals() const
{
return reinterpret_cast<const QList<const Terminal*>&>(
const_cast<ControlUnit*>(this)->terminals());
}
}


Название: Re: Достоинства static_cast
Отправлено: Igors от Сентябрь 20, 2012, 06:41
значи я знаю, что у меня никогда не будет потерей точностей и говорю это компилятору, чтобы не сыпал варнинг... Хотя мне кажется тут на лицо, опасность, т.к. double'ы умножаются потом еще и складываются, когда-нибудь выстрел будет в ногу... поэтому если я не уверен, что (x * m.m00 + y * m.m10) и (x * m.m10 + y * m.m11) - поместится во float, я вообще не буду писать никаких приведениев ни в С++ стиле ни в Си, оставлю так, пусть компилятор говорит мне об потенциальной опасности в будущем...
Влазит одинаково во float и double, опасность переполнения та же самая. Просто float будет больше терять точность т.к. умеет хранить меньше цифр - ну это забота вызывающего, если он подавал на вход float значит считал ему точности хватит.

А в остальном я с Вами согласен, хотя мне больше нравится (float) или float(). Вариант "без всяких приведений" также считаю разумным, только придется запретить этот варнинг т.к. их будет очень много (это маленький кусочек показан).

Остальные от ответа благоразумно уклонились и предпочитают отпихиваться общими словами - ну это их право :)


Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 20, 2012, 10:22
Код
C++ (Qt)
QWidget * w;
..
QLineEdit * e = static_cast <QLineEdit *> (w);
 
А какой тут смысл? Иерархия классов меняется крайне редко.

Какой смысл писать так:
Код:
 *ioX = static_cast<float>(x * m.m00 + y * m.m10); //or in C-style (float)(x * m.m00 + y * m.m10) 
 *ioY = static_cast<float>(x * m.m10 + y * m.m11); //or in C-style (float)(x * m.m00 + y * m.m10)
Этот каст использует неявное преобразование типов, определенный самим языком.

На счет заметности в коде вопрос спорный. Если писать функцию длиною не более 75 строк, то все преобразования заметны.



Название: Re: Достоинства static_cast
Отправлено: DmitryM от Сентябрь 20, 2012, 10:32
Ну, если они меняются, то константой они быть не могут (с точки зрения логики, а не возможностей языка).
Хотя ваш вариант сработает.
cv квалификаторы указывают на намерения, а не на "логику".