From 1bf8fcbb31e39bc3c667f99e2c333bdb3536494b Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Fri, 3 Nov 2023 14:21:04 +0100 Subject: [PATCH] ENH: Add `Deref(T *)`, to ease dereferencing a pointer safely `Deref(ptr)` throws an exception when its argument (`ptr`) is null. --- Modules/Core/Common/include/itkDeref.h | 59 ++++++++++++++++++++++ Modules/Core/Common/test/CMakeLists.txt | 1 + Modules/Core/Common/test/itkDerefGTest.cxx | 48 ++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 Modules/Core/Common/include/itkDeref.h create mode 100644 Modules/Core/Common/test/itkDerefGTest.cxx diff --git a/Modules/Core/Common/include/itkDeref.h b/Modules/Core/Common/include/itkDeref.h new file mode 100644 index 000000000000..10ea885ecdd4 --- /dev/null +++ b/Modules/Core/Common/include/itkDeref.h @@ -0,0 +1,59 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef itkDeref_h +#define itkDeref_h + +#include "itkMacro.h" +#include +#include + +namespace itk +{ + +/** \class DerefError + * Exception thrown when trying to dereference a null pointer. + * \ingroup ITKCommon + */ +class DerefError : public ExceptionObject +{ +public: + // Inherit the constructors from its base class. + using ExceptionObject::ExceptionObject; + + /** Runtime information support. */ + itkTypeMacro(DerefError, ExceptionObject); +}; + + +/** Dereferences the specified pointer, when the pointer is not null. Throws a `DerefError` exception when the pointer + * is null. Aims to avoid undefined behavior from accidentally dereferencing a null pointer. + */ +template +T & +Deref(T * const ptr) +{ + if (ptr == nullptr) + { + itkSpecializedMessageExceptionMacro( + DerefError, "The pointer passed to `itk::Deref(T*)` is null! T's typeid name: `" << typeid(T).name() << '`'); + } + return *ptr; +} +} // namespace itk + +#endif diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index ac28228a8d1d..6d33194a483b 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -1706,6 +1706,7 @@ set(ITKCommonGTests itkBuildInformationGTest.cxx itkConnectedImageNeighborhoodShapeGTest.cxx itkConstantBoundaryImageNeighborhoodPixelAccessPolicyGTest.cxx + itkDerefGTest.cxx itkExceptionObjectGTest.cxx itkFixedArrayGTest.cxx itkImageNeighborhoodOffsetsGTest.cxx diff --git a/Modules/Core/Common/test/itkDerefGTest.cxx b/Modules/Core/Common/test/itkDerefGTest.cxx new file mode 100644 index 000000000000..6ba0f73dafbc --- /dev/null +++ b/Modules/Core/Common/test/itkDerefGTest.cxx @@ -0,0 +1,48 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +// First include the header file to be tested: +#include "itkDeref.h" +#include +#include "itkObject.h" + + +// Tests that `Deref(ptr)` throws a `DerefError` exception when its argument is null. +TEST(Deref, ThrowsExceptionWhenArgumentIsNull) +{ + const auto check = [](const auto & ptr) { EXPECT_THROW(itk::Deref(ptr), itk::DerefError); }; + + check(static_cast(nullptr)); + check(static_cast(nullptr)); + check(static_cast(nullptr)); +} + + +// Tests that `Deref(ptr)` returns the same reference as `*ptr`, when `ptr` is not null. +TEST(Deref, ReturnsReferenceWhenArgumentIsNotNull) +{ + const auto check = [](const auto & ptr) { + const auto & ref = itk::Deref(ptr); + EXPECT_EQ(&ref, &*ptr); + }; + + constexpr int i{}; + check(&i); + check(std::make_unique().get()); + check(itk::Object::New().get()); +}