在回调函数

时间:2015-09-09 06:21:21

标签: c++ oop design-patterns

图书馆的代码段:

class Client{
public:
    class CallBack {
    public:
        virtual void onData(Client* caller, std::string& data) =0;
    };

    Client(CallBack* callback):m_callBack(callback){}
    virtual ~Client(){}
    void onData(std::string data) {
        m_callBack->onData(this, data);
        m_totalDataVol += data.size();
    }

private:
    CallBack* m_callBack;
    int m_totalDataVol = 0;
}

应用程序的代码段:

class AppHandler: public Client::Callback {
    void onData(Client* caller, std::string& data) {
        /* Some complex logic and check certain conditions*/
            delete caller; // Application will crash, due to 
                           // accessing member of deleted object (m_totalDataVol)
    }
}

此外,Caller对象(Client类的实例)归应用程序所有,而Application没有限制删除它。

我如何克服这个问题?

非常复杂的情况: 基础库的Client类可以由另一个库(ClientEx类)扩展,应用程序可能使用该扩展库(不是基础库)

1 个答案:

答案 0 :(得分:2)

让你的回调返回bool,表明调用者是否应该删除自己。不要从回调中删除客户端。

此外,如果data.size == 0,是否需要调用回调? Client可以在调用回调之前检查这个条件,并自行删除(或以其他方式处理它)。

如果仍然需要调用回调,也许您可​​以通过在调用后检查客户端中的条件来避免更改返回类型:

void onData(std::string data) {
    m_callBack->onData(this, data);
    if (data.size() != 0) {
        m_totalDataVol += data.size();
    }
    else {
        delete this;
    }
}

或者,如果您确实必须允许回调删除客户端,那么您需要某种方式来跟踪客户端何时被删除,您可以在客户端本身中使用。这意味着保持对另一个对象的引用:

class Client{
public:
    class CallBack {
    public:
        virtual void onData(Client* caller, std::string& data) =0;
    };

    Client(CallBack* callback):m_callBack(callback){}, was_deleted(nullptr)
    virtual ~Client(){
        if (was_deleted) *was_deleted = true;
    }
    void onData(std::string data) {
        bool *was_deleted = new bool();
        this->was_deleted = was_deleted;
        m_callBack->onData(this, data);
        if (! *was_deleted) {
            m_totalDataVol += data.size();
            this->was_deleted = nullptr;
        }
        delete was_deleted;
    }

private:
    CallBack* m_callBack;
    int m_totalDataVol = 0;
    // When issuing a callback, holds a pointer to a flag that can
    // be used to track if this object has been deleted:
    bool * was_deleted;
}

(请注意,上面的解决方案不是线程安全的,但可能是这样做的。还要注意上面的代码没有编译,就像你问题中的示例代码没有 - 我有尽可能地匹配原始代码;原则应适用于实际代码。)

相关问题