Planned maintenance: From Sunday 8th December 10:00 CET there will be changes to try and solve the caching issues that have been experienced. If anyone has a problem connecting after this period then please PM @AndyS or any of the moderators.

Tieing the lifetime of an object to that of a lambda?



  • I am struggling to understand if there is a way to effectively attach a destructor to the lifetime of a lambda. I can see this being a potentially powerful way to tie objects to lambdas and have the scope of the lambda manage any allocated memory. I know through a closure/capture (not sure I am using that term right) you can copy an object or get a reference to an object. For instance I could do the equivalent of this:

    auto lamb = [new QObject()](){
        //some code
    }
    

    However, I would like to do that, but have the new QObject() be destroyed when the lambda goes out of scope. I looked through the website I referenced, but could not make heads or tails if this is even a thing. I am hoping that maybe there is some magic I can do with smart pointers that would allow me to do this. Maybe I just answered my own question:

    auto lamb = [unique_pointer obj(new QObject())]() {
        // some code
    }
    

    I know the syntax is prob not right, but hopefully you get my intent.

    Can we do this somehow? I could I guess create an object that is a function pointer that uses RAII as well. Or has an operator() defined for it.



  • Apparently C++ 14 allows capturing unique_pointers:

    class TestObj2 : public QObject{
        Q_OBJECT
    public:
        TestObj2(){}
        ~TestObj2(){
            qInfo() << "I am free!";
        }
    
    };
    
    void lamb_test(){
        std::unique_ptr<TestObj2> u = std::make_unique<TestObj2>();
        qInfo() << u.get(); // pointer not null
        auto lamb = [u = std::move(u)](){
            qInfo() << u.get(); // pointer not null
        };
        qInfo() << u.get(); // pointer null
        lamb();
    }
    

    Output:

    TestObj2(0x55d93909c250)
    QObject(0x0)
    TestObj2(0x55d93909c250)
    I am free!
    

    Not sure why second qInfo output is saying QObject though. But it does free the memory when the lambda goes out of scope.



  • Okay, found out how to use bind this way too:

        void test_func(std::unique_ptr<QObject>& obj){
            qInfo() << obj.get();
        }
    
        ...
    
        std::unique_ptr<QObject> u2(new TestObj2);
    
        // to use bind this way you must pass smart pointer by reference
        auto lamb2 = std::bind([](auto& obj){qInfo() << obj.get();}, std::move(u2));
        // or 
        auto lamb2 = std::bind(test_func, std::move(u2));
    
        lamb2();
    

    I dunno, this is just really cool. I like how you can use bind as well. This makes for some interesting callback options for signals. You could put a bunch of binds in a vector. When you clear the vector the binds and the objects tied to those functors just magically get cleaned up.



  • I've been following this with interest and wondered about the lifetime of the unique_ptr. seems like you figured it out and it does what you want. Although you probably want to do some additional testing to verify how it "seems to work".

    Personally I think lambdas are way too overused, but that's just my fortran4 bias creeping in.



  • @Kent-Dorfman said in Tieing the lifetime of an object to that of a lambda?:

    Personally I think lambdas are way too overused

    I think at this point I am more interested in the "neat" factor than the utility. I think it will be a nice tool to attach objects as needed to signals, or to graft simpler signals onto more complex outputs. I could imagine this being used as a generator of objects. Lambda capture also reminds me of RAII as used in objects.

    So the technical reason for now "cause its cools, and could be useful...maybe".


Log in to reply