Is it OK to use C-style cast for built-in types?
I would not, for the following reasons:
- Casts are ugly and should be ugly and stand out in your code, and be findable using grep and similar tools.
- "Always use C++ casts" is a simple rule that is much more likely to be remembered and followed than, "Use C++ casts on user-defined types, but it's OK to use C-style casts on built-in types."
- C++ style casts provide more information to other developers about why the cast is necessary.
- C-style casts may let you do conversions you didn't intend -- if you have an interface that takes in (int*) and you were using c-style casts to pass it a const int*, and the interface changes to take in a long*, your code using c-style casts will continue to work, even if it's not what you wanted.
In C++, can we use { } for C-Style casting?
Is
int{c}
another way of casting data types?
Yes. T{value}
creates a temporary of type T
that is direct-list-initialized with the specified braced-init-list. This cast does have an advantage over T(value)
in that T{value}
can be used to create a temporary array. That would be done like
int main() {
using int_array = int[5];
for( auto e : int_array{1,2,3,4,5})
std::cout << e;
}
It also comes with the caveat that a narrowing conversion is a error
int main() {
int(10000000000ll); // warning only, still compiles
int{10000000000ll}; // hard error mandated by the standard
}
After some research on the net, I know that C++ casting is different and it have the compiler check the casting possibility at the compile time, but what are the differences between 1 and 2?
The big difference between T(value)
and (T)value
is that in T(value)
, T
must be a single word. For example
int main() {
unsigned int(10000000); // error
(unsigned int)10000000; // compiles
}
Q3: Are there any other ways to explicitly convert/cast?
Well in C++ they want you to use the C++ casts which are static_cast
, reinterpret_cast
, dynamic_cast
, and const_cast
. Those are preferred over c style cast as a c style cast will do all of those where the C++ versions have certain limitations and come with certain guarantees.
What is the difference between static_cast and C style casting?
C++ style casts are checked by the compiler. C style casts aren't and can fail at runtime.
Also, c++ style casts can be searched for easily, whereas it's really hard to search for c style casts.
Another big benefit is that the 4 different C++ style casts express the intent of the programmer more clearly.
When writing C++ I'd pretty much always use the C++ ones over the the C style.
C++ cast syntax styles
It's best practice never to use C-style casts for three main reasons:
- as already mentioned, no checking is performed here. The programmer simply cannot know which of the various casts is used which weakens strong typing
- the new casts are intentionally visually striking. Since casts often reveal a weakness in the code, it's argued that making casts visible in the code is a good thing.
- this is especially true if searching for casts with an automated tool. Finding C-style casts reliably is nearly impossible.
As palm3D noted:
I find C++-style cast syntax too verbose.
This is intentional, for the reasons given above.
The constructor syntax (official name: function-style cast) is semantically the same as the C-style cast and should be avoided as well (except for variable initializations on declaration), for the same reasons. It is debatable whether this should be true even for types that define custom constructors but in Effective C++, Meyers argues that even in those cases you should refrain from using them. To illustrate:
void f(auto_ptr<int> x);
f(static_cast<auto_ptr<int> >(new int(5))); // GOOD
f(auto_ptr<int>(new int(5)); // BAD
The static_cast
here will actually call the auto_ptr
constructor.
Difference between static casting styles in C++ for primitive values
In this case, they are equivalent. You should prefer the C++-style casts (static_cast
, reinterpret_cast
, dynamic_cast
and const_cast
) for all types, no matter if primitive or not, because you want to state your exact intention. The C-style cast is mightier than the others (taken individually) and should be avoided exactly for that reason.
If you apply a static_cast
where it is not allowed, the compiler will complain. If you apply a C-style cast in the same situation, you may, for example, silently get a reinterpret_cast
with undefined run-time behaviour instead of a compiler error.
What exactly is or was the purpose of C++ function-style casts?
Function style casts bring consistency to primitive and user defined types. This is very useful when defining templates. For example, take this very silly example:
template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}
My silly_cast
function will work for primitive types, because it's a function-style cast. It will also work for user defined types, so long as class T has a single argument constructor that takes a U or U const &.
template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}
class Foo {};
class Bar {
public:
Bar(Foo const&) {};
};
int main() {
long lg = 1L;
Foo f;
int v = silly_cast<int>(lg);
Bar b = silly_cast<Bar>(f);
}
When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?
static_cast
is the first cast you should attempt to use. It does things like implicit conversions between types (such as int
to float
, or pointer to void*
), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast
isn't necessary, but it's important to note that the T(something)
syntax is equivalent to (T)something
and should be avoided (more on that later). A T(something, something_else)
is safe, however, and guaranteed to call the constructor.
static_cast
can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual
inheritance. It does not do checking, however, and it is undefined behavior to static_cast
down a hierarchy to a type that isn't actually the type of the object.
const_cast
can be used to remove or add const
to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast
). It is important to note that modifying a formerly const
value is only undefined if the original variable is const
; if you use it to take the const
off a reference to something that wasn't declared with const
, it is safe. This can be useful when overloading member functions based on const
, for instance. It can also be used to add const
to an object, such as to call a member function overload.
const_cast
also works similarly on volatile
, though that's less common.
dynamic_cast
is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast
will seek out the desired object and return it if possible. If it can't, it will return nullptr
in the case of a pointer, or throw std::bad_cast
in the case of a reference.
dynamic_cast
has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual
inheritance. It also can only go through public inheritance - it will always fail to travel through protected
or private
inheritance. This is rarely an issue, however, as such forms of inheritance are rare.
reinterpret_cast
is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int
, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast
is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast
cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.
C-style cast and function-style cast are casts using (type)object
or type(object)
, respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:
const_cast
static_cast
(though ignoring access restrictions)static_cast
(see above), thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_cast
It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast
, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast
will succeed or reinterpret_cast
will fail. Even then, consider the longer, more explicit option.
C-style casts also ignore access control when performing a static_cast
, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.
Related Topics
Why, Really, Deleting an Incomplete Type Is Undefined Behaviour
Constexpr Function Parameters as Template Arguments
Undefined Reference to Winmain (C++ Mingw)
Generate Include File Name in a MACro
If I Want to Specialise Just One Method in a Template, How to Do It
Possible Causes for Boost Not Being Found by Cmake in Certain Situations
Better Shading on Bw Display While Rendering Filled Surfaces
Where Would You Use a Friend Function VS. a Static Member Function
Derived Class with Non-Virtual Destructor
Difference Between 'Strcpy' and 'Strcpy_S'
How to Declare Variables of Different Types in the Initialization of a for Loop
How to Get the Executable Name of a Window
What Happens When You Bit Shift Beyond the End of a Variable