title: Hazard Pointers with well defined allocators in C++
body: <p>I read the following note in Chapter 7 of the book <a href="https://www.manning.com/books/c-plus-plus-concurrency-in-action" rel="nofollow noreferrer">C++ Concurrency in Action</a> (Page 194). My question is, is there any allocator in the standard library, for which what we do in <a href="https://en.wikipedia.org/wiki/Hazard_pointer" rel="nofollow noreferrer">Hazard Pointers</a> is well defined?</p>
  
  <blockquote>
    <p>Using hazard pointers like this relies on the fact that it's safe to use the value of a pointer after the object it references has been deleted. This is technically undefined behavior if you are using the default implementation of new and delete, so either you need to ensure that your implementation permits it, or you need to use a custom allocator that permits such usage.</p>
  </blockquote>
  
  <p><a href="https://stackoverflow.com/questions/44182049/pointers-in-c-after-delete">Here</a> is a relevant post to the undefined/unspecified behavior I am talking about here. The piece of code the above note is referring to is the following:</p>
  
  <pre><code>std::shared_ptr&lt;T&gt; pop() {
    std::atomic&lt;void*&gt;&amp; hp=get_hazard_pointer_for_current_thread();
    node* old_head=head.load();
    node* temp;
    do {
      temp=old_head;         // Here we are reading (not dereferencing) a pointer that might have been deleted already
      hp.store(old_head);    // And here
      old_head=head.load();
    } while(old_head!=temp); // And here
    // ...
  }
  </code></pre>
  
  <p>In fact, I would say the same problem exists when Reference Counting is used instead of Hazard Pointers (the book does not make such a claim). The following is how one pushes an element into a stack using reference counting (Page 208). The whole purpose of the while-loop in this code is to make sure value of <code>new_node.ptr-&gt;next</code> is valid, and that involves reading a pointer that might have been already deleted.</p>
  
  <pre><code>void push(T const&amp; data) {
    counted_node_ptr new_node;
    new_node.ptr=new node(data);
    new_node.external_count=1;
    new_node.ptr-&gt;next=head.load(std::memory_order_relaxed)
    while(!head.compare_exchange_weak(
                  new_node.ptr-&gt;next,
                  new_node,
                  std::memory_order_release,
                  std::memory_order_relaxed)); }
  </code></pre>