有時我需要創建構造函數花費很長時間執行的對象。 這會導致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的答案的提示,我試着寫一個工廠,將承擔相應的責任在同步或異步的方式創建一個對象:
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