Привязка С++ к weak_ptr не работает

У меня есть простой тест, в котором я пытаюсь связать аргумент weak_ptr с глобальной функцией, которая принимает weak_ptr и вызывает метод, если вспомогательный указатель все еще действителен.

Кажется, это работает, когда я создаю лямбду со слабым указателем. Это также работает, если я вызываю глобальный метод напрямую с параметром weak_ptr. Однако, если я заранее привяжу глобальную функцию к weak_ptr, она, похоже, не сработает. Следующий упрощенный код иллюстрирует вопрос.

Я должен упустить что-то простое. Любые подсказки?

#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();
}

Результирующий вывод:

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

Ожидается, что первое weakPrintValue напечатает значение (7)


person kman    schedule 13.09.2014    source источник


Ответы (3)


Я думаю, вы хотите обернуть weak_ptr в ref(), чтобы оценить его лениво:

function<void()> weakPrintValue = bind(callWeakFunction, ref(weakValue));
person John Zwinck    schedule 13.09.2014
comment
Спасибо, захват по ссылке был проблемой. Поскольку это был первый ответ, который идентифицировал это, я приму это как ответ. Спасибо - person kman; 13.09.2014

Я бы не ожидал, что это сработает. В обоих случаях вы фиксируете начальное значение weak_value, когда оно пусто. Чтобы на него повлияло последующее присвоение ему, вам нужно вместо этого захватить по ссылке. Значит в лямбде нужно [&weak_value], а для бинда нужно

bind(callWeakFunction, cref(weakValue));
person Alan Stokes    schedule 13.09.2014
comment
Вы правы, у меня была ошибка копирования в моей лямбде, которую я исправил. Я вижу, что требование захвата по ссылке имеет смысл. - person kman; 13.09.2014

Я считаю, что bind() захватывает weakValue по значению. Он возвращает результирующий объект, который имеет собственную копию weakValue. Когда вы меняете локальный weakValue, это не влияет на копию внутри объекта, возвращаемого bind().

person GreenScape    schedule 13.09.2014