Move assignment operator is not moving my shared_ptr

I’m having some trouble with my move assignment operator, and maybe I’m just misunderstanding what’s going on. My SignalHolder object below is meant to hold a shared pointer to a Signal object and call its detach() method as soon as the SignalHolder is destroyed. Since destroying the object automatically causes the signal to be broken, it’s important that only one exists. Hence I’m using move semantics to ensure only one exists.

Anyhow, even though I’ve written a move assignment operator, it doesn’t seem to be moving my shared_ptr. If I add break point to the end of the assignment method, both *this and c point to the same object. I though std::move was supposed to move the shared_ptr to *this and leave c with a nullptr? What am I doing wrong here?

class SignalHolder
{
    std::shared_ptr<SignalCallbackBase> _target;
    inline static int idIdx = 0;

    int id;

public:
    SignalHolder(std::shared_ptr<SignalCallbackBase> target = nullptr) :
        _target(target)
    {
        id = idIdx++;
        qDebug() << "SignalHolder construct " << id;
    }

    SignalHolder(const SignalHolder&) = delete;
    SignalHolder(const SignalHolder&& c) :
        _target(std::move(c._target))
    {
        qDebug() << "SignalHolder move construct " << id;
    }

    ~SignalHolder()
    {
        qDebug() << "SignalHolder destruct " << id;
        detach();
    }

    SignalHolder& operator=(SignalHolder const&) = delete;
    SignalHolder& operator=(SignalHolder const&& c)
    {
        qDebug() << "SignalHolder assign move " << id;
        _target = std::move(c._target);

        //Break point here
        int j = 9;
    }

    void detach() {
        qDebug() << "SignalHolder detach " << id;
        if (_target)
            _target->detach();

        _target = nullptr;
    }
};


SignalHolder makeHolder()
{
    auto s = std::make_shared<SignalCallbackBase>();
    return SignalHolder(s);
}

int main()
{
    SignalHolder a;
    a = makeHolder();

}

Answer

Parameter c is declared as const, it can’t be moved. Move operation is supposed to perform modification on the object to be moved. In _target = std::move(c._target);, the copy assignment operator but not move assignment operator of std::shared_ptr gets called. (The move assignment operator of std::shared_ptr takes rvalue-reference to non-const, which can’t bind to const objects.)

You should remove the const qualifier too.

SignalHolder& operator=(SignalHolder && c)
{
    qDebug() << "SignalHolder assign move " << id;
    _target = std::move(c._target);

    //Break point here
    int j = 9;
    return *this;
}

BTW: You lost the return statement in operator=.

Leave a Reply

Your email address will not be published. Required fields are marked *