С++ static_cast - более безопасный способ. Зачем?

Я слышал, что статическое приведение — более безопасный способ приведения.

Допустим, у меня есть следующий код:

int nValue = 48;
char ch = nValue;

Это неявное литье. Но менять 4 байта на 1 байт небезопасно. Если я изменю этот код на этот:

int nValue = 48;
char ch = static_cast<char>(nValue);

Это было бы безопаснее. Зачем? что делает его безопаснее? Он все еще меняет 4 байта на 1 байт.


person user2320928    schedule 05.05.2014    source источник
comment
Это не безопаснее для компьютера, но более очевидно для всех, кто читает исходный код.   -  person PeterT    schedule 05.05.2014
comment
явное приведение типов указывает компилятору, что вы знаете, что делаете. Компилятор не предупредит вас, потому что, если вы сделали это явно, можно с уверенностью предположить, что вы знаете о риске. Я не уверен, что это то, о чем вы спрашиваете, поэтому я просто оставлю комментарий.   -  person Paweł Stawarz    schedule 05.05.2014
comment
Будет полезно, если вы изучите, что означает более безопасный. Поскольку вы где-то это слышали, мы не знаем, что это слово значит для вас.   -  person Robert Harvey    schedule 05.05.2014
comment
Если приведение небезопасно, то стандартное приведение пройдет без предупреждения, а static_cast выдаст ошибку компиляции. Небезопасность не видна в вашем примере, но рассмотрим два разных класса A и B (не связанные наследованием или чем-то еще). Теперь рассмотрим два указателя A* a и B* b. Стандартное приведение, такое как b = (B*)a, будет работать без предупреждения, хотя b было бы очень небезопасно использовать. static_cast приведет к ошибке компиляции, не позволяющей вам запускать вашу программу, пока вы ее не исправите.   -  person barak manos    schedule 05.05.2014
comment
@Deduplicator Первый пример вполне верен. Сужающие неявные преобразования — это всего лишь ошибка в C++11 внутри фигурных скобок. До C++11 и в C++11 вне фигурных скобок они разрешены.   -  person    schedule 05.05.2014
comment
Но менять 4 байта на 1 байт небезопасно — это безопасно, если вы знаете, что значение в int находится в диапазоне char!   -  person M.M    schedule 05.05.2014


Ответы (2)


static_cast не безопаснее, чем неявное преобразование. Однако вы, возможно, читали, что static_cast безопаснее, чем приведение C. Это потому, что он допускает только «разумные» приведения. Некоторые примеры разумного приведения могут быть между числовыми типами, void * к другому указателю, ptr базового класса к производному классу ptr. Например:

class Base {};
class D1 : public Base {};
class D11 {};
...
Base *ptr_to_Base(...); // Get from somewhere.
D11 *p = (D11 *) ptr_to_Base; // No compiler error! I need new eyeglasses!
D11 *p2 = static_cast<D11 *>(ptr_to_Base); // This gives you a compiler error.

Обратите внимание, что static_cast все еще может допускать плохие приведения, но не «необоснованные»:

class D2 : public Base {};
...
Base *b = new D2;
D1 *p3 = static_cast<D1 *>(b); // Wrong, but allowed by compiler.
person kec    schedule 05.05.2014
comment
Вы можете показать, что такое ptr_to_Base. А также не смешивайте D1 и Dl. - person Jarod42; 05.05.2014
comment
@ Jarod42: Я отредактирую, чтобы добавить определение ptr_to_Base. Но я намеренно использовал два имени, которые легко спутать, чтобы мотивировать использование. - person kec; 05.05.2014
comment
Я согласен с Jarod42. Мне потребовалась пара минут, чтобы понять, чем отличаются объявления указателей. L и 1 почти идентичны, поэтому я не мог понять, что вы пытаетесь сказать. - person shawn1874; 05.05.2014
comment
@shawn1874: Хорошо, думаю, мотивация менее важна, чем ясность. Я отредактирую. - person kec; 05.05.2014
comment
@shawn1874: Хорошо, теперь это D11, что, надеюсь, ясно, но правдоподобная опечатка, которую кто-то может сделать. - person kec; 05.05.2014

В этом случае я готов предположить, что static_cast не по своей сути безопаснее. Что эффективно делает приведение, так это говорит компилятору предположить, что результат будет соответствовать char и, возможно, не предупреждать вас об усечении данных. Если вы опустите приведение, компиляторы могут предупредить (особенно если вы запросите это), что возможна потеря данных.

Не связанный с вашим вопросом, но, безусловно, связанный с этим, static_cast безопаснее, чем приведения типов reinterpret_cast и C-стиля, потому что он имеет гораздо более ограниченный набор допустимых преобразований, которые он может выполнять.

person Mark B    schedule 05.05.2014