在回调称为C ++后删除对象

时间:2015-09-22 13:46:05

标签: c++ c++11

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

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

3 个答案:

答案 0 :(得分:1)

如果你想删除该函数,唯一的方法是以某种方式存储对象。但是,这会引发所有权问题:谁是异步http请求的所有者,它应该调用回调?

在这种情况下,执行GCs作业实际上使代码非常清晰。但是,如果你想让它更适应C ++,我可能会选择类似于std::async的类似承诺的界面。这样,同步代码路径可以更容易地存储promise对象。

你问了一个代码示例,所以有:

典型方法如下:

{
    DownloadData* p = new DownloadData(15, [](auto data){
        print(data)
    });
    p->sendHttpRequest();
}

数据可用后,即可打印。但是,您可以从另一端&#34;:

查看问题&#34;
{
    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的实现超出了本答案的范围,但在网上可以获得大量资源。承诺和期货的概念不是C ++特有的东西。

答案 1 :(得分:1)

你可以将它们放在vectorlist中,getHttpResponse()设置一个标志而不是delete this完成后再设置一个标志,然后再设置另一部分代码偶尔遍历列表寻找已完成的请求。

这也可以让你实现超时。如果请求未在一天内返回,则可能不会发送,您应该删除该对象。

答案 2 :(得分:0)

如果调用者保留对下载对象的引用,那么它可以在下载信号结束时将其擦除:

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 ...
相关问题