diff --git a/Config/BaseDefines.hh b/Config/BaseDefines.hh
index 1614f47860fb63362de33455bfbac3509943c8ba..e287137a959d67b6152758f3a5f43b630aee9a36 100644
--- a/Config/BaseDefines.hh
+++ b/Config/BaseDefines.hh
@@ -49,3 +49,12 @@
 #define sprintf_s snprintf
 #endif
 
+// Concatenate with one level of indirection to resolve __LINE__
+#define BASE_CONCAT_IMPL(a, b) a##b
+#define BASE_CONCAT(a, b) BASE_CONCAT_IMPL(a, b)
+
+// Create a unique variable name by combining the given name with the current
+// line. Note that this deliberately uses __LINE__ instead of __COUNTER__
+// because this allows referring to the same name multiple times within the same
+// line/macro.
+#define BASE_UNIQUE_NAME(name) BASE_CONCAT(name, __LINE__)
diff --git a/Utils/CMakeLists.txt b/Utils/CMakeLists.txt
index d8193ad60558a13c1d39d2b5e37b4fed81d6d92e..7fc0247c9187e6d99a32f71b1a72facccdd07fbe 100644
--- a/Utils/CMakeLists.txt
+++ b/Utils/CMakeLists.txt
@@ -8,6 +8,7 @@ set(my_headers
    ${CMAKE_CURRENT_SOURCE_DIR}/OptionT.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/OStringStream.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/RedirectStream.hh
+   ${CMAKE_CURRENT_SOURCE_DIR}/Scope.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/StopWatch.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/Thread.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/ThrowError.hh
diff --git a/Utils/Scope.hh b/Utils/Scope.hh
new file mode 100644
index 0000000000000000000000000000000000000000..25c59b5b1b17c1fcdb2008a1e64c5d5f0f08699e
--- /dev/null
+++ b/Utils/Scope.hh
@@ -0,0 +1,66 @@
+// (C) Copyright 2022 by Autodesk, Inc.
+
+#ifndef BASE_SCOPE_HH_INCLUDED
+#define BASE_SCOPE_HH_INCLUDED
+
+#include <Base/Config/BaseDefines.hh>
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace Scope
+{
+
+// Helper class that executes a function when the objects is destroyed.
+template <typename FuncT>
+class ExitT
+{
+public:
+  explicit ExitT(const FuncT& _func) : func_(_func) {}
+  explicit ExitT(FuncT&& _func) : func_(std::move(_func)) {}
+  ~ExitT() { func_(); }
+
+private:
+  FuncT func_;
+};
+
+// Helper function to create an ExitT object that deduces the template type.
+// Note we need this because we cannot use decltype on lambdas directly.
+template <typename FuncT>
+auto make_exit(FuncT&& _func)
+{
+  return ExitT<std::remove_reference_t<decltype(_func)>>(
+      std::forward<FuncT>(_func));
+}
+
+// Call FUNC at the end of the current scope.
+#define SCOPE_ON_EXIT(FUNC) \
+  auto BASE_UNIQUE_NAME(on_exit) = Scope::make_exit(FUNC)
+
+
+// Create a backup of VAR and restore it at the end of scope.
+#define SCOPE_VARIABLE_RESTORE(VAR) \
+  SCOPE_ON_EXIT( std::bind([&VAR](const auto& _var) { VAR = _var; }, VAR))
+
+
+// Set NEW_VAL by using SETTER and restore OLD_VAL at the end of the scope.
+#define SCOPE_VARIABLE_CHANGE(SETTER, NEW_VAL, OLD_VAL) \
+  SCOPE_ON_EXIT(std::bind(SETTER, OLD_VAL)); \
+  SETTER(NEW_VAL)
+
+
+// Assign NEW_VAL to VAR and restore VAR to its original value at the end of the
+// scope.
+#define SCOPE_VARIABLE_CHANGE_SIMPLE(VAR, NEW_VAL) \
+  SCOPE_VARIABLE_RESTORE(VAR); \
+  VAR = NEW_VAL
+
+
+
+} // namespace Scope
+
+//=============================================================================
+#endif //BASE_SCOPE_HH_INCLUDED
+//=============================================================================
+