2011-07-13 41 views
1

我有一個情況,我有一個shared_ptr基類的子類。C++ shared_ptr繼承內存泄漏

當shared_ptr去刪除指針時,只有父析構函數被調用。

父母的析構是虛擬的,孩子不是,雖然我已經在所有組合中進行了實驗。

我有valgrind中的程序,它顯示內存是在創建對象時在新語句中創建的。我知道父析構函數正在被調用,但孩子的不是。

這是孩子:

class NetworkUserAgent : public bbs::UserAgent 
{ 
friend class Server; 

public: 
    NetworkUserAgent(boost::asio::io_service &ioService, size_t _szBuffer=512u); 
    ~NetworkUserAgent(); 

    void asyncRead(); 
    void doneRead(std::shared_ptr< std::vector<char> > pBuf, 
        const boost::system::error_code &error, size_t byTrans); 

    void writeTo(const std::string &msg); 
    void doneWrite(const boost::system::error_code &error, size_t byTrans); 

void close(); 

private: 
    boost::asio::ip::tcp::socket socket_; 
    const size_t szBuffer; 
}; 

父:

class UserAgent 
{ 
public: 
    //'structors 
    UserAgent(); 
    virtual ~UserAgent(); 

    //commication 
    virtual void writeTo(const std::string &msg)=0; 
    std::function<void(std::string&)> dataRead; 

    //user management 
    void login(AccessLevel _accessLevel, int userId, const std::string &_userName); 
    void logout(); 

    //Accessors 
    AccessLevel UserAccessLevel() const; 
    const std::string &UserName() const; 
    const int &UserId() const; 
    bool LoggedIn() const; 

    //shared to allow reference to child type 
    std::shared_ptr<ContextAgentData> contextAgentData; 
private: 
    std::string userName; 
    int userId; 

    AccessLevel accessLevel; 
}; 

用法:

void Server::reset() 
{ 
    shared_ptr<NetworkUserAgent> client (new NetworkUserAgent(ioService)); 
    acceptor_.async_accept(client->socket_, 
     [=] (const boost::system::error_code &error) 
      { this->clientAccepted(client, error); } 
     ); 
} 

void Server::clientAccepted(shared_ptr<NetworkUserAgent> client, 
           const boost::system::error_code &error) 
{ 
    if(error) return; 
    cout << "[] New client has connected" << endl; 

    //Generalise to Network useragent 
    shared_ptr<UserAgent> uaClientPtr=client; 
    context->receiveUserAgent(uaClientPtr); 
    client->asyncRead(); 
    reset(); 
} 

The rest of the code can be seen here

謝謝。

另外請注意上面的代碼仍然是一個在工作中。

編輯:我錯了孩子的析構函數被調用,

NetworkUserAgent::~NetworkUserAgent() 
{ 
    this->close(); 
} 

void NetworkUserAgent::close() 
{ 
    if(!socket_.is_open()) return; //socket is already closed 
    //one or more of these functions are probably redundant 
    cout << "send request" <<endl; 
    socket_.shutdown(ip::tcp::socket::shutdown_send); 
    cout << "cancel" <<endl; 
    socket_.cancel(); 
    cout <<"close"<<endl; 
    socket_.close(); 
    cout << "done" <<endl; 
} 

編輯: 我做更多的測試,我恐怕這個問題是複雜的比我希望的。當物品被銷燬時,析構函數會被調用,但問題是一旦UserAgent進入系統,它不會被銷燬。有些東西正在被摧毀。

如果它使得和差異是幾個容器的shared_ptr到useragent,當一個包含摧毀是內部調用的元素的析構函數?

請讓我知道我可以提供什麼來解決這個問題。

+1

它不是從問題的代碼貼清醒時共享指針應予以刪除。我查看了鏈接中的代碼(順便提一下),那裏的代碼太多了。你能否詳細說明你希望何時刪除共享指針?你怎麼確定孩子的析構函數沒有被調用(它不記錄父類的東西)? – Chad

+1

只是爲了顯示'std :: shared_ptr'正確處理這種情況的簡單示例:http://ideone.com/TRXVu。我不得不第二個乍得關於你是否確定正確的析構函數沒有被調用的問題? –

+0

請提供可複製的可運行代碼來重現問題。切片出現在您已省略的代碼中的某處非常有可能。 –

回答

2

有在UserAgent的一個DATAREAD的std ::功能,最終得到設置爲包含一個std一個lambda :: shared_ptr的本身停止它的自我形式自毀。我添加了一個close()方法並將std :: function設置爲默認值。

現在一切都很好,它刪除精細

感謝您的幫助,任何方式

0

我懷疑你的對象被切片了,雖然我沒有一個測試環境。

嘗試其中之一:

shared_ptr<UserAgent> uaClientPtr = boost::static_pointer_cast<UserAgent>(client); 
shared_ptr<UserAgent> uaClientPtr = boost::dynamic_pointer_cast<UserAgent>(client); 
+0

這會更安全,但在這裏是不必要的,因爲這兩種類型已知彼此繼承。不應發生切片。 –

0

void Server::reset()auto_ptr就足夠了。

在第二種情況下,我會做以下內容:

void Server::clientAccepted(shared_ptr<NetworkUserAgent> client, const boost::system::error_code error) 
{ 
    if(error) return; 
    cout << "[] New client has connected" << endl; 
    context->receiveUserAgent(client); 
    client->asyncRead(); 
    this->reset(); 
} 
+0

這很整潔,但問題仍然存在 – 111111