2015-09-09 11 views
6

Mã từ thư viện:Xóa đối tượng người gọi một cách an toàn trong một chức năng gọi lại phân khúc

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; 
} 

phân khúc Mã từ ứng dụng:

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) 
    } 
} 

Ngoài Caller đối tượng (instance của lớp Client) được sở hữu bởi ứng dụng và Ứng dụng không hạn chế để xóa ứng dụng đó.

Làm cách nào để khắc phục sự cố này?

kịch bản rất phức tạp: Client lớp của thư viện cơ sở có thể được kéo dài thêm một thư viện khác (ClientEx lớp) và các ứng dụng có thể sử dụng thư viện mở rộng (Không phải là thư viện cơ sở)

Trả lời

2

đã gọi lại của bạn trả về một bool cho biết người gọi có nên tự xóa hay không. Không xóa ứng dụng khách khỏi cuộc gọi lại.

Ngoài ra, cuộc gọi lại cần phải được gọi ở tất cả nếu data.size == 0? Client có thể kiểm tra tình trạng này trước khi gọi lại gọi lại, và tự xóa nó (hoặc xử lý nó một cách thích hợp).

Nếu gọi lại vẫn cần phải được gọi, có lẽ bạn có thể tránh được việc thay đổi kiểu trả về chỉ bằng cách kiểm tra các điều kiện trong các khách hàng sau khi cuộc gọi:

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

Ngoài ra, nếu bạn thực sự phải cho phép gọi lại để xóa ứng dụng khách, sau đó bạn cần một số cách theo dõi khi khách hàng đã bị xóa mà bạn có thể sử dụng trong chính máy khách. Điều này có nghĩa giữ một tham chiếu đến một đối tượng khác:.

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; 
} 

(Lưu ý rằng giải pháp trên không phải là thread-an toàn, nhưng có thể có thể được thực hiện để Cũng lưu ý các mã trên không biên dịch, cũng giống như các mẫu mã trong câu hỏi của bạn không - tôi đã cố gắng để phù hợp với mã ban đầu cũng như có thể; nguyên tắc nên được áp dụng cho mã thực).

+0

Nhà phát triển ứng dụng nên biết điều đó. Nhưng trong trường hợp này tôi không thể thêm như vậy trên đầu để phát triển ứng dụng. Điều khác là làm thế nào để thực thi rằng "không xóa đối tượng người gọi". Và đây chỉ là một mã mẫu, nhưng trong thực hiện thực sự nó cần phải thêm logic phức tạp trong hàm "onData" của lớp Client. – Janaka

+0

Xin lỗi, tôi không hiểu phần đầu tiên của nhận xét của bạn. Liên quan đến thứ hai của bạn, điều đó thực sự đủ điều kiện như là câu hỏi của riêng nó. Tôi muốn đề nghị làm cho destructor riêng tư hoặc được bảo vệ. – davmac

+0

Sẽ dẫn đến việc thực hiện cồng kềnh bằng cách làm cho trình tự hủy riêng tư hoặc được bảo vệ. Vì vậy, tôi đang tìm kiếm thiết kế tốt hơn, – Janaka

Các vấn đề liên quan