diff --git a/.github/workflows/itk_dict.txt b/.github/workflows/itk_dict.txt index d5403d90bff..3926df557f6 100644 --- a/.github/workflows/itk_dict.txt +++ b/.github/workflows/itk_dict.txt @@ -45,6 +45,7 @@ Cz DDataFrameobject Dz Dasarathy +Deref Dij Dinstein DownsamplerType diff --git a/Modules/Core/Common/include/itkDeref.h b/Modules/Core/Common/include/itkDeref.h new file mode 100644 index 00000000000..10ea885ecdd --- /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 ac28228a8d1..6d33194a483 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 00000000000..6ba0f73dafb --- /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()); +}