title: std::algorithm functions lambda capture called several times
body: <p>As far as I know, lambda capture variable lifecycle is bound to lifecycle of lamda object. For example, in this case:</p>
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;string&gt;
  #include &lt;vector&gt;
  
  using namespace std;
  
  class SomeCla {
  public:
      constexpr SomeCla(int i, float f) noexcept : _i(i), _f(f) {}
  
      ~SomeCla() {
          puts(&quot;dtor&quot;);
      }
  
      SomeCla(const SomeCla&amp;) = default;
      SomeCla(SomeCla&amp;&amp;) = default;
  
      SomeCla&amp; operator=(const SomeCla&amp;) = default;
      SomeCla&amp; operator=(SomeCla&amp;&amp;) = default;
  
      constexpr float total() const noexcept { return static_cast&lt;float&gt;(_i) + _f; }
  
  private:
      int _i;
      float _f;
  };
  
  int main() {
      vector&lt;float&gt; vec = { 1.0f };
  
      const auto filler = [someCla = SomeCla(1, 2.0f)](vector&lt;float&gt;&amp; someVec, int val) {
          someVec.push_back(someCla.total() + static_cast&lt;float&gt;(val));
      };
  
      for (int i = 0; i &lt; 10; ++i) {
          filler(vec, i * 3);
      }
  
      return static_cast&lt;int&gt;(vec.size());
  }
  </code></pre>
  <p>Output is:</p>
  <pre><code>dtor
  </code></pre>
  <p>&quot;dtor&quot; was put only once even if we're calling lamda several times, which is expected.</p>
  <p>But there are strange things are about std::algorithm functions. If we use them:</p>
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;string&gt;
  #include &lt;vector&gt;
  #include &lt;algorithm&gt;
  
  using namespace std;
  
  class SomeCla {
  public:
      constexpr SomeCla(int i, float f) noexcept : _i(i), _f(f) {}
  
      ~SomeCla() {
          puts(&quot;dtor&quot;);
      }
  
      SomeCla(const SomeCla&amp;) = default;
      SomeCla(SomeCla&amp;&amp;) = default;
  
      SomeCla&amp; operator=(const SomeCla&amp;) = default;
      SomeCla&amp; operator=(SomeCla&amp;&amp;) = default;
  
      constexpr float total() const noexcept { return static_cast&lt;float&gt;(_i) + _f; }
  
  private:
      int _i;
      float _f;
  };
  
  int main() {
      vector&lt;float&gt; vec = { 1.0f };
      erase_if(vec, [someCla = SomeCla(1, 2.0f)](float ele) {
          return ele == someCla.total();
      });
  
      puts(&quot;continue&quot;);
  
      {
          const auto filler = [someCla = SomeCla(1, 2.0f)](vector&lt;float&gt;&amp; someVec, int val) {
              someVec.push_back(someCla.total() + static_cast&lt;float&gt;(val));
          };
  
          for (int i = 0; i &lt; 10; ++i) {
              filler(vec, i * 3);
          }
      }
  
      puts(&quot;continue2&quot;);
  
      ignore = none_of(vec.cbegin(), vec.cend(), [someCla = SomeCla(1, 2.0f)](float ele) { return ele == -1.0f; });
  
      puts(&quot;heyyyyyyyyyyyyy&quot;);
  
      ignore = any_of(vec.cbegin(), vec.cend(), [someCla = SomeCla(1, 2.0f)](float ele) { return ele == 1.0f; });
  
      return static_cast&lt;int&gt;(vec.size());
  }
  </code></pre>
  <p>Output will be like:</p>
  <pre><code>dtor
  dtor
  dtor
  dtor
  dtor
  dtor
  dtor
  continue
  dtor
  continue2
  dtor
  dtor
  dtor
  dtor
  dtor
  dtor
  heyyyyyyyyyyyyy
  dtor
  dtor
  dtor
  dtor
  dtor
  dtor
  dtor
  </code></pre>
  <p>7 &quot;dtor&quot; on std::erase_if, 6 &quot;dtor&quot; on std::none_of, 7 &quot;dtor&quot; on std::any_of and only 1 &quot;dtor&quot; on normal call of lambda (as expected). And these numbers are independent from container size. I tried and got same numbers.</p>
  <p>So, the question is, is it a bug or dependent on implementation details of std::algorithm functions? It seems, these std::algorithm functions probably constructs and destructs lamda object several times, that's the why our lambda capture variable was constructed and destructed several times.</p>
  <p>By the way, another strange thing is these numbers (which is 2) on MSVC build are lower than GCC and Clang but still more than 1. Here is MSVC output:</p>
  <pre><code>dtor
  dtor
  continue
  dtor
  continue2
  dtor
  dtor
  heyyyyyyyyyyyyy
  dtor
  dtor
  </code></pre>
  <p>Here it can be tested: <a href="https://godbolt.org/z/nWd77c9o6" rel="nofollow noreferrer">https://godbolt.org/z/nWd77c9o6</a></p>
  <p>For now, I decided not to create lambda capture variables (if they are not basic types) on calling std::algorithm functions, I'll create the variable and pass by reference on lambda capture instead.</p>