On Mon, Apr 13, 2015 at 01:28:05PM -0400, Ehsan Akhgari wrote:
> On 2015-04-13 5:26 AM, Nicolas B. Pierron wrote:
> >On 04/10/2015 07:47 PM, Ehsan Akhgari wrote:
> >>On 2015-04-10 1:41 PM, Nicolas B. Pierron wrote:
> >>>>Also, what is the alternative? Acquiring a nsCOMPtr/nsRefPtr inside the
> >>>>Lambda constructor (or whatever it's called)?
> >>>
> >>>Yes, another option would be to ensure that the lambda cannot be used
> >>>after a specific point.
> >>>
> >>>nsINode* myNode;
> >>>auto callFoo = MakeScopedLambda([&]() {
> >>>    myNode->Foo();
> >>>})
> >>>TakeLambda(callFoo);
> >>>
> >>>Any reference to the lambda after the end of the innermost scope where
> >>>MakeScopedLambda is used can cause a MOZ_CRASH.
> >>
> >>How would you detect that at compile/run time?
> >>
> >
> >Simply by replacing the reference to the lambda inside callFoo at the
> >end of the scope, and replace it by a constructing a dummy function
> >which expects the same type of arguments as the lambda, but calls
> >MOZ_CRASH instead.
> 
> Sorry, my question was: how do you implement this with C++?  (As in, how
> would an actual implementation work?)

That actually seems kind of straight forward.  You want to have an
object that wraps the provided lambda in callFoo and then nukes the
wrapping when the scope exits.  So I guess it would look something like
this (totally untested).

template<typename T>
class ScopedLambda
{
        template<typename U>
        class LambdaHolder
        {
                LambdaHolder(const LambdaHolder& other)
                {
                if (!other.valid) {
                        valid = false;
                        return;
                        }

                other.master->Add(this);
                mLambda = other.mLambda;
                valid = true;
                }

                ...

                void Revoke() { valid = false; }
        
                void Call()
                {
                        if (valid) /* do magic with vargs to pass
                        arguments to mLambda */ ;
                }

        private:
                T mLambda;
                ScopedLambda<T>* master;
                bool valid;
        };

        ScopedLambda(T lambda) : mLambda(lambda) {}
        ~ScopedLambda()
        {
                for (LambdaHolder* h: holders) { h->revoke(); }
        }

        // Try to force passing ScopedLambda foo to a function to result in the
        // function getting a LambdaHolder.
        operator LambdaHolder()
        {
                LambdaHolder l;
                l.master = this;
                l.mLambda = mLambda;
                l.valid = true;
                return l;
        }

        ScopedLambda(const ScopedLamba&) = delete;
        ScopedLambda(ScopedLambda&&) = delete;

        T mLambda;
        List<LambdaHolder<T>*> holders;
        };

        or actually you might be able to do the same thing my having
        ScopedLambda allocate an object on the heap that's ref counted.

        Trev

> 
> _______________________________________________
> dev-platform mailing list
> dev-platform@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to