[saferecl.hp.holder] # 32 Concurrency support library [[thread]](./#thread) ## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder) ### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder) #### 32.11.3.4 Class hazard_pointer [saferecl.hp.holder] #### [32.11.3.4.1](#general) General [[saferecl.hp.holder.general]](saferecl.hp.holder.general) namespace std {class hazard_pointer {public: hazard_pointer() noexcept; hazard_pointer(hazard_pointer&&) noexcept; hazard_pointer& operator=(hazard_pointer&&) noexcept; ~hazard_pointer(); bool empty() const noexcept; template T* protect(const atomic& src) noexcept; template bool try_protect(T*& ptr, const atomic& src) noexcept; template void reset_protection(const T* ptr) noexcept; void reset_protection(nullptr_t = nullptr) noexcept; void swap(hazard_pointer&) noexcept; };} [1](#general-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13488) An object of type hazard_pointer is either empty or[*owns*](#def:owning,hazard_pointer "32.11.3.4.1 General [saferecl.hp.holder.general]") a hazard pointer[.](#general-1.sentence-1) Each hazard pointer is owned by exactly one object of type hazard_pointer[.](#general-1.sentence-2) [*Note [1](#general-note-1)*: An empty hazard_pointer object is different from a hazard_pointer object that owns an unassociated hazard pointer[.](#general-1.sentence-3) An empty hazard_pointer object does not own any hazard pointers[.](#general-1.sentence-4) — *end note*] #### [32.11.3.4.2](#ctor) Constructors, destructor, and assignment [[saferecl.hp.holder.ctor]](saferecl.hp.holder.ctor) [🔗](#lib:hazard_pointer,constructor) `hazard_pointer() noexcept; ` [1](#ctor-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13508) *Postconditions*: *this is empty[.](#ctor-1.sentence-1) [🔗](#lib:hazard_pointer,constructor_) `hazard_pointer(hazard_pointer&& other) noexcept; ` [2](#ctor-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13519) *Postconditions*: If other is empty, *this is empty[.](#ctor-2.sentence-1) Otherwise,*this owns the hazard pointer originally owned by other;other is empty[.](#ctor-2.sentence-2) [🔗](#lib:hazard_pointer,destructor) `~hazard_pointer(); ` [3](#ctor-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13533) *Effects*: If *this is not empty, destroys the hazard pointer owned by *this, thereby ending its current protection epoch[.](#ctor-3.sentence-1) [🔗](#lib:operator=,hazard_pointer) `hazard_pointer& operator=(hazard_pointer&& other) noexcept; ` [4](#ctor-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13546) *Effects*: If this == &other is true, no effect[.](#ctor-4.sentence-1) Otherwise, if *this is not empty, destroys the hazard pointer owned by *this, thereby ending its current protection epoch[.](#ctor-4.sentence-2) [5](#ctor-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13553) *Postconditions*: If other was empty, *this is empty[.](#ctor-5.sentence-1) Otherwise, *this owns the hazard pointer originally owned by other[.](#ctor-5.sentence-2) If this != &other is true, other is empty[.](#ctor-5.sentence-3) [6](#ctor-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13560) *Returns*: *this[.](#ctor-6.sentence-1) #### [32.11.3.4.3](#mem) Member functions [[saferecl.hp.holder.mem]](saferecl.hp.holder.mem) [🔗](#lib:empty,hazard_pointer) `bool empty() const noexcept; ` [1](#mem-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13573) *Returns*: true if and only if *this is empty[.](#mem-1.sentence-1) [🔗](#lib:protect,hazard_pointer) `template T* protect(const atomic& src) noexcept; ` [2](#mem-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13584) *Effects*: Equivalent to:T* ptr = src.load(memory_order::relaxed);while (!try_protect(ptr, src)) {}return ptr; [🔗](#lib:try_protect,hazard_pointer) `template bool try_protect(T*& ptr, const atomic& src) noexcept; ` [3](#mem-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13600) *Mandates*: T is a hazard-protectable type[.](#mem-3.sentence-1) [4](#mem-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13604) *Preconditions*: *this is not empty[.](#mem-4.sentence-1) [5](#mem-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13608) *Effects*: Performs the following steps in order: - [(5.1)](#mem-5.1) Initializes a variable old of type T* with the value of ptr[.](#mem-5.1.sentence-1) - [(5.2)](#mem-5.2) Evaluates reset_protection(old)[.](#mem-5.2.sentence-1) - [(5.3)](#mem-5.3) Assigns the value of src.load(memory_order​::​acquire) to ptr[.](#mem-5.3.sentence-1) - [(5.4)](#mem-5.4) If old == ptr is false, evaluates reset_protection()[.](#mem-5.4.sentence-1) [6](#mem-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13619) *Returns*: old == ptr[.](#mem-6.sentence-1) [🔗](#lib:reset_protection,hazard_pointer) `template void reset_protection(const T* ptr) noexcept; ` [7](#mem-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13630) *Mandates*: T is a hazard-protectable type[.](#mem-7.sentence-1) [8](#mem-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13634) *Preconditions*: *this is not empty[.](#mem-8.sentence-1) [9](#mem-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13638) *Effects*: If ptr is a null pointer value, invokes reset_protection()[.](#mem-9.sentence-1) Otherwise, associates the hazard pointer owned by *this with *ptr, thereby ending the current protection epoch[.](#mem-9.sentence-2) [10](#mem-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13645) *Complexity*: Constant[.](#mem-10.sentence-1) [🔗](#lib:reset_protection,hazard_pointer_) `void reset_protection(nullptr_t = nullptr) noexcept; ` [11](#mem-11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13656) *Preconditions*: *this is not empty[.](#mem-11.sentence-1) [12](#mem-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13660) *Postconditions*: The hazard pointer owned by *this is unassociated[.](#mem-12.sentence-1) [13](#mem-13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13664) *Complexity*: Constant[.](#mem-13.sentence-1) [🔗](#lib:swap,hazard_pointer) `void swap(hazard_pointer& other) noexcept; ` [14](#mem-14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13675) *Effects*: Swaps the hazard pointer ownership of this object with that of other[.](#mem-14.sentence-1) [*Note [1](#mem-note-1)*: The owned hazard pointers, if any, remain unchanged during the swap and continue to be associated with the respective objects that they were protecting before the swap, if any[.](#mem-14.sentence-2) No protection epochs are ended or initiated[.](#mem-14.sentence-3) — *end note*] [15](#mem-15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13685) *Complexity*: Constant[.](#mem-15.sentence-1) #### [32.11.3.4.4](#nonmem) Non-member functions [[saferecl.hp.holder.nonmem]](saferecl.hp.holder.nonmem) [🔗](#lib:make_hazard_pointer) `hazard_pointer make_hazard_pointer(); ` [1](#nonmem-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13698) *Effects*: Constructs a hazard pointer[.](#nonmem-1.sentence-1) [2](#nonmem-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13702) *Returns*: A hazard_pointer object that owns the newly-constructed hazard pointer[.](#nonmem-2.sentence-1) [3](#nonmem-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13706) *Throws*: May throw bad_alloc if memory for the hazard pointer could not be allocated[.](#nonmem-3.sentence-1) [🔗](#lib:swap,hazard_pointer_) `void swap(hazard_pointer& a, hazard_pointer& b) noexcept; ` [4](#nonmem-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13718) *Effects*: Equivalent to a.swap(b)[.](#nonmem-4.sentence-1)