- Hands-On System Programming with C++
- Dr. Rian Quinn
- 698字
- 2021-07-02 14:42:29
Type safety in C++
Standard C is not a type-safe language. Type safety refers to protections put in place to prevent one type from being confused with another type. Some languages, such as ADA, are extremely type-safe, providing so many protections that the language, at times, can be frustrating to work with.
Conversely, languages such as C are so type-unsafe that hard-to-find type errors occur frequently, and often lead to instability.
C++ provides a compromise between the two approaches, encouraging reasonable type safety by default, while providing mechanisms to circumvent this when needed.
For example, consider the following code:
/* Example: C */
int *p = malloc(sizeof(int));
// Example: C++
auto p = new int;
Allocating an integer on the heap in C requires the use of malloc(), which returns void *. There are several issues with this code that are addressed in C++:
- C automatically converts the void * type to int *, meaning that an implicit type conversion has occurred even though there is no connection between the type the user stated and the type returned. The user could easily allocate short (which is not the same thing as int, a topic we will discuss in Chapter 3, System Types for C and C++). The type conversion would still be applied, meaning that the compiler would not have the proper context to detect that the allocation was not large enough for the type the user was attempting to allocate.
- The size of the allocation must be stated by the programmer. Unlike C++, C has no understanding of the type that is being allocated. Thus, it is unaware of the size of the type, and so the programmer must explicitly state this. The problem with this approach is that hard-to-find allocation bugs can be introduced. Often, the type that is provided to sizeof() is incorrect (for example, the programmer might provide a pointer instead of the type itself, or the programmer might change the code later on, but forget to change the value being provided to sizeof()). As stated previously, there is no connection between what malloc() allocates and returns, and the type the user attempts to allocate, providing an opportunity to introduce a hard-to-find logic error.
- The type must be explicitly stated twice. malloc() returns void *, but C implicitly converts to whatever pointer type the user states—which means a type has been declared twice (in this case, void * and int *). In C++, the use of auto means that the type is only declared once (in this case, int states the type is an int *), and auto will take on whatever type is returned. The use of auto and the removal of implicit type conversions means whatever type is declared in the allocation is what the p variable will take on. If the code after this allocation expects a different type to the one p takes on, the compiler will know about it at compile time in C++, while a bug like this would likely not be caught in C until runtime, when the program crashes (we hope this code is not controlling an airplane!).
In addition to the preceding example of the dangers of implicit type casting, C++ also provides run-time type information (RTTI). This information has many uses, but the most important use case involves the dynamic_cast<> operator, which performs runtime type checking.
Specifically, converting from one type to another can be checked during runtime, to ensure a type error doesn't occur. This is often seen when performing the following:
- Polymorphic type conversions: In C, polymorphism is possible, but it must be done manually, a pattern that is seen often in kernel programming. C, however, doesn't have the ability to determine whether a pointer was allocated for a base type or not, resulting in the potential for a type error. Conversely, C++ is capable of determining at runtime whether a provided pointer is being cast to the proper type, including when using polymorphism.
- Exception support: When catching an exception, C++ uses RTTI (essentially dynamic_cast<>), to ensure that the exception being thrown is caught by the proper handler.