vendredi 5 juin 2015

Dynamically-Allocated Implementation-Class std::async-ing its Member

Consider an operation with a standard asynchronous interface:

std::future<void> op();

Internally, op needs to perform a (variable) number of asynchronous operations to complete; the number of these operations is finite but unbounded, and depends on the results of previous asynchronous operations.

Here's a (bad) attempt:

/* An object of this class will store the shared execution state in the members;
*    the asynchronous op is its member. */
class shared
{
private:
    // shared state

private:
    // Actually does some operation (asynchronously).
    void do_op()
    {
        ...
        // Might need to launch more ops.
        if(...)
            launch_next_ops();
    }

public:
    // Launches next ops
    void launch_next_ops()
    {
        ...
        std::async(&shared::do_op, this);
    }
}

std::future<void> op()
{
    shared s;
    s.launch_next_ops();
    // Return some future of s used for the entire operation.
    ...
    // s destructed - delayed BOOM!
};

The problem, of course is that s goes out of scope, so later methods will not work.

To amend this, here are the changes:

class shared : public std::enable_shared_from_this<shared> 
{
private:
    /* The member now takes a shared pointer to itself; hopefully 
    *    this will keep it alive. */
    void do_op(std::shared_ptr<shared> p); // [*]

    void launch_next_ops()
    {
        ...
        std::async(&shared::do_op, this, shared_from_this());
    }
}

std::future<void> op()
{
    std::shared_ptr<shared> s{new shared{}};
    s->launch_next_ops();
    ...
};

(Asides from the weirdness of a class calling its method with a shared pointer to itself, )the problem is with the line marked [*]. The compiler (correctly) warns that it's an unused variable.

Of course, it's possible to fool it somehow, but is this a fundamental indication of a problem? Is there any chance the compiler will do some optimization stuff and leave the method with a gone object? Is there a better alternative to this whole scheme?

Aucun commentaire:

Enregistrer un commentaire