時々、コンストラクタの実行に非常に時間がかかるオブジェクトを作成する必要があります。 これは、UIアプリケーションの応答性の問題につながります。オブジェクトが利用可能になったときに私を警告することへのコールバックを渡すことによって、非同期的に呼び出されるように設計コンストラクタを書くことは賢明なことができれば C++ 11の非同期コンストラクタ
は、だから私は思っていました。以下ははサンプルコードです:
class C
{
public:
// Standard ctor
C()
{
init();
}
// Designed for async ctor
C(std::function<void(void)> callback)
{
init();
callback();
}
private:
void init() // Should be replaced by delegating costructor (not yet supported by my compiler)
{
std::chrono::seconds s(2);
std::this_thread::sleep_for(s);
std::cout << "Object created" << std::endl;
}
};
int main(int argc, char* argv[])
{
auto msgQueue = std::queue<char>();
std::mutex m;
std::condition_variable cv;
auto notified = false;
// Some parallel task
auto f = []()
{
return 42;
};
// Callback to be called when the ctor ends
auto callback = [&m,&cv,¬ified,&msgQueue]()
{
std::cout << "The object you were waiting for is now available" << std::endl;
// Notify that the ctor has ended
std::unique_lock<std::mutex> _(m);
msgQueue.push('x');
notified = true;
cv.notify_one();
};
// Start first task
auto ans = std::async(std::launch::async, f);
// Start second task (ctor)
std::async(std::launch::async, [&callback](){ auto c = C(callback); });
std::cout << "The answer is " << ans.get() << std::endl;
// Mimic typical UI message queue
auto done = false;
while(!done)
{
std::unique_lock<std::mutex> lock(m);
while(!notified)
{
cv.wait(lock);
}
while(!msgQueue.empty())
{
auto msg = msgQueue.front();
msgQueue.pop();
if(msg == 'x')
{
done = true;
}
}
}
std::cout << "Press a key to exit..." << std::endl;
getchar();
return 0;
}
あなたは、この設計で任意の欠点を参照していますか?または、より良いアプローチがあるかどうか知っていますか? JoergBの答えのヒントに続い
EDIT
、私は、同期または非同期の方法でオブジェクトを作成する責任を負う工場を書き込もうとしました:
template <typename T, typename... Args>
class FutureFactory
{
public:
typedef std::unique_ptr<T> pT;
typedef std::future<pT> future_pT;
typedef std::function<void(pT)> callback_pT;
public:
static pT create_sync(Args... params)
{
return pT(new T(params...));
}
static future_pT create_async_byFuture(Args... params)
{
return std::async(std::launch::async, &FutureFactory<T, Args...>::create_sync, params...);
}
static void create_async_byCallback(callback_pT cb, Args... params)
{
std::async(std::launch::async, &FutureFactory<T, Args...>::manage_async_byCallback, cb, params...);
}
private:
FutureFactory(){}
static void manage_async_byCallback(callback_pT cb, Args... params)
{
auto ptr = FutureFactory<T, Args...>::create_sync(params...);
cb(std::move(ptr));
}
};
コンストラクタ内でstd :: asyncを使用してみましたか?私はあなたがコールバックに非同期を入れて、クラス自体のメンバーとして結果を格納することができると思います。 – thang
@thang私はそれを試してみたいと思います...私にとっての問題は、オブジェクトを作成しても、まだ使用する準備ができていないということです。この場合、isValid()メソッドが役立ちます。 – Cristiano
ええ、あなたはisValidやwaitValidなどを追加することができます。そういうわけで、すべてがクラスにカプセル化されています...同じ機能、ちょっとちょっとだけ。 – thang