title: Why calling via weak_ptr is so slow?
body: <p>I have read the question <a href="https://stackoverflow.com/questions/2748091/whats-the-performance-penalty-of-weak-ptr">What&#39;s the performance penalty of weak_ptr?</a> but my own tests show different results.</p>
  
  <p>I'm making delegates with smart pointers. The simple code below shows reproduces the performance issues with <code>weak_ptr</code>. Can anybody tell me why?</p>
  
  <pre><code>#include &lt;chrono&gt;
  #include &lt;functional&gt;
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;stdint.h&gt;
  #include &lt;string&gt;
  #include &lt;utility&gt;
  
  struct Foo
  {
      Foo() : counter(0) { incrStep = 1;}
  
      void bar()
      {
          counter += incrStep;
      }
  
      virtual ~Foo()
      {
          std::cout &lt;&lt; "End " &lt;&lt; counter &lt;&lt; std::endl;
      }
  private:
      uint64_t counter;
      uint64_t incrStep;
  };
  
  void pf(const std::string &amp;md, const std::function&lt;void()&gt; &amp;g)
  {
      const auto st = std::chrono::high_resolution_clock::now();
      g();
      const auto ft = std::chrono::high_resolution_clock::now();
      const auto del = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(ft - st);
      std::cout &lt;&lt; md &lt;&lt; " \t: \t" &lt;&lt; del.count() &lt;&lt; std::endl;
  }
  </code></pre>
  
  <p>And the test:</p>
  
  <pre><code>int main(int , char** )
  {
      volatile size_t l = 1000000000ULL;
      size_t maxCounter = l;
  
      auto a = std::make_shared&lt;Foo&gt;();
      std::weak_ptr&lt;Foo&gt; wp = a;
  
      pf("call via raw ptr        ", [=](){
          for (size_t i = 0; i &lt; maxCounter; ++i)
          {
              auto p = a.get();
              if (p)
              {
                  p-&gt;bar();
              }
          }
      });
  
      pf("call via shared_ptr      ", [=](){
          for (size_t i = 0; i &lt; maxCounter; ++i)
          {
              if (a)
              {
                  a-&gt;bar();
              }
          }
      });
  
      pf("call via weak_ptr       ", [=](){
          std::shared_ptr&lt;Foo&gt; p;
          for (size_t i = 0; i &lt; maxCounter; ++i)
          {
              p = wp.lock();
              if (p)
              {
                  p-&gt;bar();
              }
          }
      });
  
      pf("call via shared_ptr copy", [=](){
          volatile std::shared_ptr&lt;Foo&gt; p1 = a;
          std::shared_ptr&lt;Foo&gt; p;
          for (size_t i = 0; i &lt; maxCounter; ++i)
          {
              p = const_cast&lt;std::shared_ptr&lt;Foo&gt;&amp; &gt;(p1);
              if (p)
              {
                  p-&gt;bar();
              }
          }
      });
  
      pf("call via mem_fn         ", [=](){
          auto fff = std::mem_fn(&amp;Foo::bar);
          for (size_t i = 0; i &lt; maxCounter; ++i)
          {
              fff(a.get());
          }
      });
  
      return 0;
  }
  </code></pre>
  
  <p>Results:</p>
  
  <pre><code>$ ./test
  call via raw ptr            :   369
  call via shared_ptr         :   302
  call via weak_ptr           :   22663
  call via shared_ptr copy    :   2171
  call via mem_fn             :   2124
  End 5000000000
  </code></pre>
  
  <p>As you can see, <code>weak_ptr</code> is 10 times slower than <code>shared_ptr</code> with copying and <code>std::mem_fn</code> and 60 times slower than using raw ptr or <code>shared_ptr.get()</code></p>