Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.07.2012, 21:02   #11
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Гром Посмотреть сообщение
Я думаю, потому, что этим говорят: "Так, вот щас будет полный писец, тартар, тьма и педерастия; не пытайтесь повторить это дома, я честно предупредил!" Т.е. дело не в кастах, а в сишной конструкции - если вместо каста написать ее, то будет непонятно, осознанно ли это сделано, или автор забивает гвозди микроскопом, когда мог бы использовать, например, static_cast.
Разумеется, подразумевается, что у кодера есть полное понимание, и он никогда не использует приведение в стиле Си или reinterpret_cast, когда мог бы обойтись малой кровью.
То есть, исключительно из идейных соображений использовать менее удобную конструкцию там, где можно было бы использовать более удобную конструкцию, с эквивалентным профитом?

Рассмотрим пример:

Код:
Some agent; //содержит виртуальные методы, множественное наследование и бла бла бла
Статик_каст уже не канает, ибо с полиморфами нужно пользовать динамик_каст.

Код:
void* ptr = &agent;
Some * test = (Some*)ptr;
Ну и в чем проблема? На кой болт мне упали все эти статики, реинтер, и динамики?

Я уж не говорю, что сишное приведение вообще ничем не отличается от рентерп_каста. Только синтаксисом.

Последний раз редактировалось _Bers; 23.07.2012 в 21:05.
_Bers вне форума Ответить с цитированием
Старый 23.07.2012, 21:12   #12
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Только синтаксисом.
Ну зачем-то же его придумали?
Может разные компиляторы по разному обрабатывают эту операцию? Может где-то какой-то компиль всетки преобразовывает как-нибудь хитро?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 23.07.2012, 21:21   #13
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Ну зачем-то же его придумали?
Может разные компиляторы по разному обрабатывают эту операцию? Может где-то какой-то компиль всетки преобразовывает как-нибудь хитро?
По стандарту, приведение в стиле си сначала дергает статик_каст, и если не канает - дергает рентрп_каст.

А последний отличается от первого только отсутствием проверок.

Итого: можно считать, что сишное приведение ничем не отличается от реинтерп_каста.
_Bers вне форума Ответить с цитированием
Старый 23.07.2012, 22:02   #14
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
А последний отличается от первого только отсутствием проверок.

Итого: можно считать, что сишное приведение ничем не отличается от реинтерп_каста.
Глупости. Рекомендуется использовать разные преобразования для разных операций для полного понимания процесса. reinterpret_cast используется в смысле "интерпретировать значение как нечто иное, чем оно представлено ныне в системе типов", а static_cast значит "преобразовать значение к другому типу". Не говоря уж о dynamic_cast, который производит проверку на корректность приведения типов во время выполнения через RTTI.
Код:
class A {
public:
  explicit A (double d) { }
};

void fn (A a) { }

int main () {
  double d = 1.5;
  fn (d); // ошибка
  fn (reinterpret_cast<A> (d)); // ошибка
  fn (static_cast<A> (d)); // правильно
  fn ((A) d); // правильно
}
Но, безусловно, в основном следующее утверждение верно
Цитата:
Сообщение от _Bers
То есть, исключительно из идейных соображений
netrino вне форума Ответить с цитированием
Старый 23.07.2012, 22:14   #15
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
Код:
class A {
public:
  explicit A (double d) { }
};

void fn (A a) { }

int main () {
  double d = 1.5;
  fn (d); // ошибка
  fn (reinterpret_cast<A> (d)); // ошибка
  fn (static_cast<A> (d)); // правильно
  fn ((A) d); // правильно
}
Спасибо за интересный код. Значит действительно, отличия между сишным и reinterpret_cast существуют.

Только, если честно, то я так и не понял: почему статик_каст прокатил, а реинтерпрет_каст не прокатил
_Bers вне форума Ответить с цитированием
Старый 23.07.2012, 22:20   #16
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Спасибо за интересный код. Значит действительно, отличия между сишным и reinterpret_cast существуют.

Только, если честно, то я так и не понял: почему статик_каст прокатил, а реинтерпрет_каст не прокатил
Как я писал выше, reinterpret_cast используется для указания интерпретировать нечто, как что-то другое. То есть не преобразовывать его по-настоящему, а лишь интерпретировать иначе. Например считать, что некая переменная ptr имеет не тип int *, а double *, или что значение в переменной типа size_t на самом деле указатель char *. static_cast производит непосредственно преобразование, с усечением данных когда надо, или вызовом конструктора.
netrino вне форума Ответить с цитированием
Старый 23.07.2012, 22:25   #17
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
Как я писал выше, reinterpret_cast используется для указания интерпретировать нечто, как что-то другое. То есть не преобразовывать его по-настоящему, а лишь интерпретировать иначе. Например считать, что некая переменная ptr имеет не тип int *, а double *, или что значение в переменной типа size_t на самом деле указатель char *. static_cast производит непосредственно преобразование, с усечением данных когда надо, или вызовом конструктора.
Известно, что приведение типа - есть создание нового объекта, посредством копирующего конструктора.

Читаю: реинтерпрет_каст не позволяет приводить одно значение к другому. Не вижу возможности проверить: он что, действительно только меняет интерпретацию ничего не создавая?

Когда я им указатели привожу, у меня разве не создаются временные копии новых объектов-указателей?
_Bers вне форума Ответить с цитированием
Старый 23.07.2012, 22:32   #18
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Известно, что приведение типа - есть создание нового объекта, посредством копирующего конструктора.

Читаю: реинтерпрет_каст не позволяет приводить одно значение к другому. Не вижу возможности проверить: он что, действительно только меняет интерпретацию ничего не создавая?

Когда я им указатели привожу, у меня разве не создаются временные копии новых объектов-указателей?
В этом нет смысла, reinterpret_cast существует исключительно для насилования системы типов, в рантайме никакого оверхеда не несёт. Временные копии будут только тех объектов, которые были переданы аргументом в reinterpret_cast (что и так очевидно)
Код:
float x;
int *y;
y = reinterpret_cast<int *> (&x); // временная копия указателя на x типом float *
netrino вне форума Ответить с цитированием
Старый 23.07.2012, 22:59   #19
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
В этом нет смысла, reinterpret_cast существует исключительно для насилования системы типов, в рантайме никакого оверхеда не несёт.
Ладно, поговорим о насилии над типами.

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

Не буду вдаваться в подробности. Спрашиваю, как знатока(!) плюсов.

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

Ниже представлен код:

Код:
//будем считать, что она упрятана где то в кишках, и не доступна снаружи. 
void Bar(void* ptr)
{
    int* test = (int*)ptr;
    cout<<"a1 = " <<*test<<endl;
    ++test;
    cout<<"a2 = " <<*(test)<<endl;
}


void Foo(int a1, int a2)
{
    Bar(&a1); //только Фуу имеет право вызвать Бар
}


int main()
{
    Foo(10,20);
    return 0;
}
Смысл в том, что копируются аргументы только один раз (вместо интов могут оказаться тяжелые классы), а дальше работа идет с одним единственным указателем. По факту, объекты-аргументы живут на стеке функции Foo

какие тут могут быть проблемы, и как гарантировать безопасную работу?
А то мало ли - компиль чего нибудь соптимизирует.

Последний раз редактировалось _Bers; 23.07.2012 в 23:02.
_Bers вне форума Ответить с цитированием
Старый 24.07.2012, 01:13   #20
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Ладно, поговорим о насилии над типами.

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

Не буду вдаваться в подробности. Спрашиваю, как знатока(!) плюсов.

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

Ниже представлен код:

Код:
//будем считать, что она упрятана где то в кишках, и не доступна снаружи. 
void Bar(void* ptr)
{
    int* test = (int*)ptr;
    cout<<"a1 = " <<*test<<endl;
    ++test;
    cout<<"a2 = " <<*(test)<<endl;
}


void Foo(int a1, int a2)
{
    Bar(&a1); //только Фуу имеет право вызвать Бар
}


int main()
{
    Foo(10,20);
    return 0;
}
Смысл в том, что копируются аргументы только один раз (вместо интов могут оказаться тяжелые классы), а дальше работа идет с одним единственным указателем. По факту, объекты-аргументы живут на стеке функции Foo

какие тут могут быть проблемы, и как гарантировать безопасную работу?
А то мало ли - компиль чего нибудь соптимизирует.
В данном конкретном случае проблемы будут на 64-битных машинах и в принципе на любых компиляторах, где размер int отличается от размера машинного слова (по нему выравниваются значения в стеке). Единственный портабельный способ гулять по чужому стеку - va_list/va_start/va_arg/va_end, так работают vprintf и друзья.

Переменное кол-во значений обязательно? Было бы лучше поискать альтернативные решения (например просто определить Bar как ф-цию, которая принимает указатели или ссылки), потому как любой из способов для плюсов будет не типо-безопасным (разве только шаблоны переменной длины из C++11).
netrino вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
malloc в С++ _Kitten_ Помощь студентам 2 12.12.2011 19:20
Malloc Sabin4ik Общие вопросы C/C++ 12 18.02.2011 01:13
функция malloc() для разного типа переменной. Serjuk Помощь студентам 46 05.01.2010 21:52
SIEGSEGV в malloc() TheVampire Общие вопросы C/C++ 0 25.09.2009 14:32
Проблема с malloc Обледеневший Общие вопросы C/C++ 7 14.09.2009 18:06