c++调用回调后删除对象



我创建了一个新对象,并设置了一个数据和一个回调,就像这样:

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,自杀是非常不可取的。是否有一个好的设计模式或方法?

您可以将它们放在vectorlist中,让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 ...

最新更新