0

I have a simple test where I am trying to bind a weak_ptr argument to a global function that takes a weak_ptr, and invokes a method if the backing pointer is still valid.

This seems to work when I create a lambda with the weak pointer. It also works if I call the global method directly, with the weak_ptr. However if I bind the global function to the weak_ptr in advance, it does not seem to work. Following watered down code illustrates the question.

I must be missing something simple. Any clues?

#include <iostream>
#include <functional>
#include <algorithm>
#include <memory>

using namespace std;

class MyValue : public enable_shared_from_this<MyValue>
{
    public:
        MyValue (int i)
        {
            value = i;
        }

        ~MyValue()
        {
        }

        int getValue() { return value; }

        void printValue() { cout << value << endl; }

    private:

        int value;
};

void callWeakFunction (weak_ptr<MyValue> weakValue)
{
    shared_ptr<MyValue> strongPtr = weakValue.lock();

    if (strongPtr)
    {
        strongPtr->printValue();
    }
    else
    {
        cout << "Sorry, your backing pointer is gone" << endl;
    }
}

int main()
{
    weak_ptr<MyValue> weakValue;

    // Try binding a global function to the weak pointer, doesn't seem to work
    function<void()> weakPrintValue = bind(callWeakFunction, weakValue);

#if 0
    // Create a lambda - this works fine
    function<void()> weakPrintValue ([&weakValue]()
                       {
                           shared_ptr<MyValue> ptr = weakValue.lock();
                           if(ptr)
                           {
                               ptr->printValue();
                           }
                           else
                           {
                               cout << "Sorry, backing pointer is gone" << endl;
                           }
                       });
#endif

    {
        shared_ptr<MyValue> value = make_shared<MyValue>(7);

        weakValue = value;

        // Backing pointer is present
        weakPrintValue();    // This does not work, but callWeakFunction (weakValue) works fine
    }

    // No backing pointer
    weakPrintValue();
}

Resulting output:

Sorry, your backing pointer is gone
Sorry, your backing pointer is gone

Expecting the first weakPrintValue to print the value (7)

kman
  • 107
  • 1
  • 8

3 Answers3

1

I think you want to wrap the weak_ptr in ref() to evaluate it lazily:

function<void()> weakPrintValue = bind(callWeakFunction, ref(weakValue));
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Thanks, capture by reference was the issue. As this was the first answer to identify this, I will accept this as the answer. Thanks – kman Sep 13 '14 at 14:34
0

I wouldn't expect either to work. In both cases you're capturing the initial value of weak_value when it is empty. To be affected by the subsequent assignment to it you need to capture by reference instead. So in the lambda you need [&weak_value], and for the bind you need

bind(callWeakFunction, cref(weakValue));
Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
  • You are right, I had a copy paste error in my lambda which I have fixed. I see the capture by reference requirement, makes sense. – kman Sep 13 '14 at 14:33
0

I believe bind() captures weakValue by value. It returns resulting object that has it's own copy of weakValue. When you change local weakValue it does not affect the copy inside of the object returned by bind().

GreenScape
  • 7,191
  • 2
  • 34
  • 64