2015-06-05 3 views
2

Рассмотрим операцию со стандартным асинхронным интерфейсом:Динамически-Выделено станд Реализация класса :: асинхронной-ки его член

std::future<void> op(); 

Внутренне, op должно выполнить (переменное) количество асинхронных операций для завершения; число этих операций является конечным, но неограниченным и зависит от результатов предыдущих асинхронных операций.

Вот (плохо) попытка:

/* 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! 
}; 

Проблема, конечно, является то, что s выходит из области видимости, поэтому позже методы не будут работать.

Чтобы изменить это, вот изменения:

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 от странности объекта вызова метода с общим указателем на себя,) проблема с линией, обозначенной [*]. Компилятор (правильно) предупреждает, что это неиспользуемая переменная.

Конечно, это можно как-то обмануть, но является ли это признаком фундаментальной проблемы? Есть ли вероятность, что компилятор будет оптимизировать аргумент и оставить метод с мертвым объектом? Есть ли лучшая альтернатива всей этой схеме? Я не считаю полученный код наиболее интуитивным.

ответ

1

Нет, компилятор не будет оптимизировать аргумент. На самом деле, это не имеет значения, как увеличение срока эксплуатации происходит от shared_from_this() привязываясь к кариесу копии ([thread.decaycopy]) в результате вызова std::async ([futures.async]/3).

Если вы хотите избежать предупреждения о неиспользуемом аргументе, просто оставьте его неназванным; компиляторы, которые предупреждают о неиспользуемых аргументах, не будут предупреждать о неиспользуемых неназванных аргументах.

Альтернатива сделать do_opstatic, а это означает, что вы должны использовать его shared_ptr аргумент; это также касается дублирования между this и shared_from_this. Поскольку это довольно громоздким, вы можете захотеть использовать лямбда для преобразования shared_from_this в this указатель:

std::async([](std::shared_ptr<shared> const& self){ self->do_op(); }, shared_from_this()); 

Если вы можете использовать C++ 14 Init-захватывает это становится еще проще:

std::async([self = shared_from_this()]{ self->do_op(); }); 
+0

Спасибо за полезный ответ! Если оставить аргумент неназванным, это то, что я делаю, и рад, что это законно. –

Смежные вопросы