From dda18034781e7f31f459a9120e187eeab93e701a Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 16:59:35 +0100 Subject: [PATCH 1/8] Create const_cast.md --- const_cast.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 const_cast.md diff --git a/const_cast.md b/const_cast.md new file mode 100644 index 0000000..25a64b1 --- /dev/null +++ b/const_cast.md @@ -0,0 +1,66 @@ +# const_cast conversion + +const_cast is an explicit cast operator that is mainly used to remove (or add) constness from/to a pointer or reference. +Before explaining const_cast, we first need to learn about top-level and low-level constness. + +## Top level const +The top level const qualifier affects the object itself. This means that the object itself is immutable. +?inline +- For variables, the const-qualifier is always top-const; +- For pointers, a top-level const makes the pointer itself immutable (so you can't reassign a new address to it). +- The top-level const for pointers can be recognized easily since it is always after the asterisk. +- For references, there is no need to add a top-level const: they are always qualified with a top-level const, since a reference itself +can never be mutated. + +```cpp +const int x = 4; // const for fundamental types is always top-level const +int* const my_pointer = /* ... */; // top level const - the pointer itself is const and cannot be reassigned +``` + +## Low level const +The low level const, unlike the top-one, does not affect the object itself. +This type of const is only useful when working with references and pointers: a low level const makes it impossible for +a pointer or reference to mutate the object that they are pointing to or referencing. + +```cpp +int not_const_variable = 5; // Note: this variable is not const +const int* pointer = ¬_const_variable; // Low level const - the object pointed to is considered const +const int& reference = not_const_variable; // Low level const +``` + +In C++, a pointer can have both top level and low level constness at the same time. + +const_cast is only able to remove or add the low-level constness, and never the top-level one (because otherwise we would break +the mutability of the object). + +## Examples +- Remove constness: +```cpp +int main() { + const int i = 0; + const int* const pointer = &i; + int* x = const_cast(pointer); // Remove low-level const from + // pointer -- valid + *const_cast(pointer) = 2000; // No compile time error, but undefined + // behavior: we cannot mutate the object x points to, because it + // has a top level const qualifier +} +``` + +- Add constness: + ```cpp + int main() { + int i = 0; + int* pointer = &i; + *const_cast(pointer) = 5; // Doesn't compile + // because a low level const qualifier has been added! +} +``` + +## const_cast might be dangerous to use +Unless you have a very good reason to, you should avoid const_cast when possible. That's because it can easily lead +to undefined behavior, and also because it's very easy to break the const-best practices when using it. + +## Also See +To learn about all the rules related to const_cast, visit +[cppreference: const_cast](https://en.cppreference.com/w/cpp/language/const_cast) From 818e754c011fde283844bd475a3479961eff34f8 Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 17:09:42 +0100 Subject: [PATCH 2/8] Update const_cast.md --- const_cast.md | 45 ++++++--------------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/const_cast.md b/const_cast.md index 25a64b1..0377662 100644 --- a/const_cast.md +++ b/const_cast.md @@ -1,37 +1,6 @@ -# const_cast conversion - +## const_cast conversion const_cast is an explicit cast operator that is mainly used to remove (or add) constness from/to a pointer or reference. -Before explaining const_cast, we first need to learn about top-level and low-level constness. - -## Top level const -The top level const qualifier affects the object itself. This means that the object itself is immutable. -?inline -- For variables, the const-qualifier is always top-const; -- For pointers, a top-level const makes the pointer itself immutable (so you can't reassign a new address to it). -- The top-level const for pointers can be recognized easily since it is always after the asterisk. -- For references, there is no need to add a top-level const: they are always qualified with a top-level const, since a reference itself -can never be mutated. - -```cpp -const int x = 4; // const for fundamental types is always top-level const -int* const my_pointer = /* ... */; // top level const - the pointer itself is const and cannot be reassigned -``` - -## Low level const -The low level const, unlike the top-one, does not affect the object itself. -This type of const is only useful when working with references and pointers: a low level const makes it impossible for -a pointer or reference to mutate the object that they are pointing to or referencing. - -```cpp -int not_const_variable = 5; // Note: this variable is not const -const int* pointer = ¬_const_variable; // Low level const - the object pointed to is considered const -const int& reference = not_const_variable; // Low level const -``` - -In C++, a pointer can have both top level and low level constness at the same time. - -const_cast is only able to remove or add the low-level constness, and never the top-level one (because otherwise we would break -the mutability of the object). +This operator is only able to remove or add the constness to **what a pointer (or reference) points to**, and *never* the constness of the object itself: otherwise, we would break the mutability of the object. ## Examples - Remove constness: @@ -42,24 +11,22 @@ int main() { int* x = const_cast(pointer); // Remove low-level const from // pointer -- valid *const_cast(pointer) = 2000; // No compile time error, but undefined - // behavior: we cannot mutate the object x points to, because it - // has a top level const qualifier + // behavior: we cannot mutate the object x points to, because it is originally const! } ``` - - Add constness: ```cpp int main() { int i = 0; int* pointer = &i; *const_cast(pointer) = 5; // Doesn't compile - // because a low level const qualifier has been added! + // since we added a const qualifier: we now cannot mutate this object's value! } ``` ## const_cast might be dangerous to use -Unless you have a very good reason to, you should avoid const_cast when possible. That's because it can easily lead -to undefined behavior, and also because it's very easy to break the const-best practices when using it. +Unless you have a very good reason to, *you should avoid const_cast* when possible. That's because it can easily lead +to undefined behavior, but also because it's very easy to break the constness-related best practices while using it. ## Also See To learn about all the rules related to const_cast, visit From f95f3a502f8deb73c9cf90bd7a20c2dda89ac1c0 Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 17:11:16 +0100 Subject: [PATCH 3/8] Update const_cast.md --- const_cast.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/const_cast.md b/const_cast.md index 0377662..2386bd1 100644 --- a/const_cast.md +++ b/const_cast.md @@ -1,6 +1,6 @@ ## const_cast conversion const_cast is an explicit cast operator that is mainly used to remove (or add) constness from/to a pointer or reference. -This operator is only able to remove or add the constness to **what a pointer (or reference) points to**, and *never* the constness of the object itself: otherwise, we would break the mutability of the object. +This operator is only able to remove or add the constness to **what a pointer (or reference) points to**, and *never* the constness of the object itself: otherwise, we would break the immutability of the object. ## Examples - Remove constness: From 32a7b379a44ea552f74366da5675e86a4416596d Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 17:11:49 +0100 Subject: [PATCH 4/8] Update const_cast.md --- const_cast.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/const_cast.md b/const_cast.md index 2386bd1..dcbb83a 100644 --- a/const_cast.md +++ b/const_cast.md @@ -8,8 +8,8 @@ This operator is only able to remove or add the constness to **what a pointer (o int main() { const int i = 0; const int* const pointer = &i; - int* x = const_cast(pointer); // Remove low-level const from - // pointer -- valid + int* x = const_cast(pointer); // Remove const from + // what the pointer points to -- valid *const_cast(pointer) = 2000; // No compile time error, but undefined // behavior: we cannot mutate the object x points to, because it is originally const! } From 39b9c7e7997ce0522a218a7814ad722c801b2b57 Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 17:25:33 +0100 Subject: [PATCH 5/8] Create dynamic_cast.md --- dynamic_cast.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 dynamic_cast.md diff --git a/dynamic_cast.md b/dynamic_cast.md new file mode 100644 index 0000000..5127259 --- /dev/null +++ b/dynamic_cast.md @@ -0,0 +1,30 @@ +## dynamic_cast conversion +dynamic_cast is an explicit cast operator that is often used when working with inheritance hierarchies, to convert pointers +(and references) from the derived class to the base class (upcasting) and the opposite (downcasting). +This operator performs a run-time check to test whether the conversion can be done, that is, it returns a null pointer +if the conversion could not be applied. This also implies a little overhead when using this cast. + +## Useful conversions +dynamic_cast is mostly used when we need to downcast a base class to its derived class. +It is often important to check whether the cast was successful: we can simply test whether the pointer returned by +dynamic_cast is nullptr, and if it is, the conversion did not work correctly. +```cpp +int main() { + Base* base = new Derived; + if (Derived* derived = dynamic_cast(base); derived != nullptr) /* Check that the conversion did not fail */ { + derived->foo(); + } + // Note: If base didn't point to a derived object, the if statement would never execute because derived would be null + delete base; +} +``` + +## Notes +Downcasting can be applied through static_cast as well, but in that case no runtime check is performed. +Unless you can prove that the conversion will not fail, you should use dymamic_cast in that it's safer and might avoid +unwanted issues. + + +## Also See +To learn about all the rules related to dynamic_cast, visit +[cppreference: dynamic_cast](https://en.cppreference.com/w/cpp/language/dynamic_cast) From 5b5a57c4592f9346dd81b2c459dd9b3e81fb3e8e Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 18:23:32 +0100 Subject: [PATCH 6/8] Update dynamic_cast.md --- dynamic_cast.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dynamic_cast.md b/dynamic_cast.md index 5127259..ba8b3d7 100644 --- a/dynamic_cast.md +++ b/dynamic_cast.md @@ -1,13 +1,13 @@ ## dynamic_cast conversion -dynamic_cast is an explicit cast operator that is often used when working with inheritance hierarchies, to convert pointers +`dynamic_cast` is an explicit cast operator that is often used when working with inheritance hierarchies, to convert pointers (and references) from the derived class to the base class (upcasting) and the opposite (downcasting). -This operator performs a run-time check to test whether the conversion can be done, that is, it returns a null pointer -if the conversion could not be applied. This also implies a little overhead when using this cast. +This operator performs a runtime check to test whether the conversion can be done: it returns a null pointer on failure. +This implies a little overhead when using it. ## Useful conversions -dynamic_cast is mostly used when we need to downcast a base class to its derived class. -It is often important to check whether the cast was successful: we can simply test whether the pointer returned by -dynamic_cast is nullptr, and if it is, the conversion did not work correctly. +`dynamic_cast` is mostly used when we need to downcast a base class to its derived class. +It is important to check whether the cast was successful: we can test whether the pointer returned by +dynamic_cast is nullptr, and if it is, the conversion failed. ```cpp int main() { Base* base = new Derived; @@ -20,11 +20,12 @@ int main() { ``` ## Notes -Downcasting can be applied through static_cast as well, but in that case no runtime check is performed. -Unless you can prove that the conversion will not fail, you should use dymamic_cast in that it's safer and might avoid +You can downcast with `static_cast` too, but no runtime check is performed. +Unless you can prove that the conversion will not fail, use use dymamic_cast in that it's safer and will avoid unwanted issues. -## Also See -To learn about all the rules related to dynamic_cast, visit +## See Also [cppreference: dynamic_cast](https://en.cppreference.com/w/cpp/language/dynamic_cast) +[how to down_cast correctly](https://stackoverflow.com/questions/52556957/how-to-use-dynamic-cast-to-downcast-correctly) +[is dynamic_cast considered bad design?](https://stackoverflow.com/questions/48612271/use-case-of-dynamic-cast) From c02e34c5a52f6f47314870368dde8aacd0c5680d Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 18:26:42 +0100 Subject: [PATCH 7/8] Update const_cast.md --- const_cast.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/const_cast.md b/const_cast.md index dcbb83a..58d14da 100644 --- a/const_cast.md +++ b/const_cast.md @@ -1,6 +1,6 @@ -## const_cast conversion -const_cast is an explicit cast operator that is mainly used to remove (or add) constness from/to a pointer or reference. -This operator is only able to remove or add the constness to **what a pointer (or reference) points to**, and *never* the constness of the object itself: otherwise, we would break the immutability of the object. +## `const_cast` conversion +`const_cast` is an explicit cast operator that is mainly used to remove (or add) constness from/to a pointer or reference. +This operator can only remove or add the constness to **what a pointer (or reference) points to**, and *never* the constness of the object itself: otherwise, we would break the immutability of the object. ## Examples - Remove constness: @@ -24,10 +24,11 @@ int main() { } ``` -## const_cast might be dangerous to use -Unless you have a very good reason to, *you should avoid const_cast* when possible. That's because it can easily lead -to undefined behavior, but also because it's very easy to break the constness-related best practices while using it. +## `const_cas`t might be dangerous to use +Unless you have a very good reason to, *you should avoid `const_cast`*. It can easily lead +to undefined behavior and it's very easy to break the constness-related best practices while using it. ## Also See -To learn about all the rules related to const_cast, visit [cppreference: const_cast](https://en.cppreference.com/w/cpp/language/const_cast) +[how to use const_cast?](https://stackoverflow.com/questions/19554841/how-to-use-const-cast) +[is const_cast safe?](https://stackoverflow.com/questions/357600/is-const-cast-safe) From 2dfe14225f36895208206dfc7c46991309896ce3 Mon Sep 17 00:00:00 2001 From: SoLetsBegin <36608065+SoWeBegin@users.noreply.github.com> Date: Wed, 9 Feb 2022 18:29:31 +0100 Subject: [PATCH 8/8] Update dynamic_cast.md --- dynamic_cast.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dynamic_cast.md b/dynamic_cast.md index ba8b3d7..21a4c5e 100644 --- a/dynamic_cast.md +++ b/dynamic_cast.md @@ -1,4 +1,4 @@ -## dynamic_cast conversion +## `dynamic_cast` conversion `dynamic_cast` is an explicit cast operator that is often used when working with inheritance hierarchies, to convert pointers (and references) from the derived class to the base class (upcasting) and the opposite (downcasting). This operator performs a runtime check to test whether the conversion can be done: it returns a null pointer on failure. @@ -7,7 +7,7 @@ This implies a little overhead when using it. ## Useful conversions `dynamic_cast` is mostly used when we need to downcast a base class to its derived class. It is important to check whether the cast was successful: we can test whether the pointer returned by -dynamic_cast is nullptr, and if it is, the conversion failed. +`dynamic_cast` is nullptr, and if it is, the conversion failed. ```cpp int main() { Base* base = new Derived; @@ -26,6 +26,6 @@ unwanted issues. ## See Also -[cppreference: dynamic_cast](https://en.cppreference.com/w/cpp/language/dynamic_cast) -[how to down_cast correctly](https://stackoverflow.com/questions/52556957/how-to-use-dynamic-cast-to-downcast-correctly) -[is dynamic_cast considered bad design?](https://stackoverflow.com/questions/48612271/use-case-of-dynamic-cast) +- [cppreference: dynamic_cast](https://en.cppreference.com/w/cpp/language/dynamic_cast) +- [how to down_cast correctly](https://stackoverflow.com/questions/52556957/how-to-use-dynamic-cast-to-downcast-correctly) +- [is dynamic_cast considered bad design?](https://stackoverflow.com/questions/48612271/use-case-of-dynamic-cast)