jeudi 23 mai 2019

How does a lambda that captures a shared_ptr by value affect its use_count()?

I am curious about the lifespan of a shared_ptr when captured by value within a lambda.

I had expected its use_count() to always be >= 1 as long as the lambda is still in memory, but my test shows something unexpected: use count falls to 0, then increments to 1 inside the lambda body...

Here's what I tested:

  1. create a shared_ptr
  2. define a lambda that captures the shared_ptr by value
  3. reset the shared_ptr
  4. run the lambda

At stage 3, the shared_ptr's use_count() falls to 0 - but the object is not destroyed. At stage 4 - inside the lambda - use_count() is back to 1. After the lambda is run, use_count() goes back to 0, but the object is not destroyed until the lambda is destroyed.

I'm wondering how / why this could be?

Shouldn't use_count() be 2 after the lambda definition and then 1 inside the lambda?


testing code on Repl.it:

#include <iostream>
#include <memory>

class Foo {
public:
  Foo( int v = 0 ) : val(v) {}
  ~Foo(){
    std::cout << "--- Foo destroyed ---" << std::endl;
  }
  int val = 0;
};

void logPtr( const std::shared_ptr<Foo>& p ){
    std::cout << "ptr: refs = " << p.use_count();
    if (p) {
      std::cout << ", val = " << p->val << std::endl;
    }
    else {
     std::cout << ", nullptr" << std::endl;
    }
}

int main() {

  std::shared_ptr<Foo> ptr = std::make_shared<Foo>( 0 );

  logPtr(ptr);

  std::cout << "--- define lambda ---\n";

  auto lambda = [=]() {

    std::cout << "--- run lambda ---\n";
    if (ptr) { ptr->val++; }
    logPtr(ptr);
    std::cout << "--- end lambda ---\n";

  };

  logPtr(ptr);

  std::cout << "--- reset ptr ---\n";
  ptr.reset();
  logPtr(ptr);

  // run lambda
  lambda();
  logPtr(ptr);

}


here is the output:

ptr: refs = 1, val = 0
--- define lambda ---
ptr: refs = 2, val = 0
--- reset ptr ---
ptr: refs = 0, nullptr
--- run lambda ---
ptr: refs = 1, val = 1
--- end lambda ---
ptr: refs = 0, nullptr
--- Foo destroyed ---

Aucun commentaire:

Enregistrer un commentaire