我创建了一个新对象,并设置了一个数据和一个回调,就像这样:
class DownloadData
{
std::function<void(int, bool)> m_callback;
int m_data;
public:
void sendHttpRequest()
{
// send request with data
}
private:
void getHttpResponse(int responseCode)
{
if (responseCode == 0)
{
// save data
m_callback(responseCode, true);
delete this;
return;
}
// some processing here
if (responseCode == 1 && some other condition here)
{
m_callback(responseCode, false);
delete this;
return;
}
}
}
现在的用法-我创建了一个新对象:
if (isNeededToDownloadTheFile)
{
DownloadData* p = new DownloadData(15, [](){});
p->sendHttpRequest();
}
但是正如你所看到的https://isocpp.org/wiki/faq/freestore-mgmt#delete-this,自杀是非常不可取的。是否有一个好的设计模式或方法?
您可以将它们放在vector
或list
中,让getHttpResponse()
在完成时设置标志而不是delete this
,然后让代码的另一部分偶尔遍历列表寻找完成的请求。
也允许你实现超时。如果请求在一天内没有返回,那么它可能不会返回,您应该删除该对象。
如果您想将delete从该函数中删除,唯一的方法就是以某种方式存储该对象。然而,这引发了所有权问题:谁是应该调用回调的异步http请求的所有者?
在这种情况下,执行gc的工作实际上使代码非常清晰。然而,如果你想让它更适合c++,我可能会选择一个类似于承诺的接口,类似于std::async
。这样,同步代码路径就更容易存储承诺对象了。
你要的是一个代码示例,所以这里是:
典型的方法是这样的:
{
DownloadData* p = new DownloadData(15, [](auto data){
print(data)
});
p->sendHttpRequest();
}
一旦数据可用,就可以打印。然而,你可以从"另一端"看这个问题:
{
Future<MyData> f = DownloadData(15).getFuture();
// now you can either
// a) synchronously wait for the future
// b) return it for further processing
return f;
}
一旦请求实际处理, f
将保存实际值。这样你就可以把它当作一个普通的值,一直推到这个值真正需要的地方,并在那里等待它。当然,如果您以异步方式使用它,您也可以为此生成另一个异步操作。
Future
的实现超出了这个答案的范围,我想,但是网上有很多资源。promise和Futures的概念并不是c++特有的。
如果调用者保留了对下载对象的引用,那么它可以在下载结束信号时删除它:
class DownloadData
{
// true until download stops (atomic to prevent race)
std::atomic_bool m_downloading;
int m_data;
std::function<void(int, bool)> m_callback;
public:
DownloadData(int data, std::function<void(int, bool)> callback)
: m_downloading(true), m_data(data), m_callback(callback) {}
void sendHttpRequest()
{
// send request with data
}
// called asynchronously to detect dead downloads
bool ended() const { return !m_downloading; }
private:
void getHttpResponse(int responseCode)
{
if (responseCode == 0)
{
// save data
m_callback(responseCode, true);
m_downloading = false; // signal end
return;
}
// some processing here
if(responseCode == 1)
{
m_callback(responseCode, false);
m_downloading = false; // signal end
return;
}
}
};
呼叫方:
std::vector<std::unique_ptr<DownloadData>> downloads;
// ... other code ...
if (isNeededToDownloadTheFile)
{
// clean current downloads by deleting all those
// whose download is ended
downloads.erase(std::remove_if(downloads.begin(), downloads.end(),
[](std::unique_ptr<DownloadData> const& d)
{
return d->ended();
}), downloads.end());
// store this away to keep it alive until its download ends
downloads.push_back(std::make_unique<DownloadData>(15, [](int, bool){}));
downloads.back()->sendHttpRequest();
}
// ... etc ...