2011-07-13 14 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になっている場合は、containsが破壊されたときに、内部の要素のデストラクタが呼び出されますか?

問題を解決するために他に何ができるのか教えてください。

+1

。私はあなたのリンクのコードを見ました(途中で眉をすませています)。あなたは、共有ポインタが削除されることを期待するときに詳しく説明できますか?子供のデストラクタが呼び出されていないことを確認してください(親のようなことは記録しません)。 – Chad

+1

'std :: shared_ptr'がそのような状況を正しく処理することを示す単純な例です:http://ideone.com/TRXVu。私はあなたが正しいデストラクタが呼び出されていないかどうかについてチャドの質問を二番目にしなければならないのですか? –

+0

問題を再現するコンパイル可能な実行可能コードを提供してください。あなたが省略したコードのどこかでスライシングが行われる可能性が非常に高いです。 –

答えて

2

:: shared_ptrの自体にそれを自己のフォームを停止破壊する。 close()メソッドを追加し、std :: functionをデフォルト値に設定しました。

は今、すべてが順調です、それはすべてのあなたの助けのための罰金

感謝を削除するどのような方法で共有ポインタを削除する必要がある場合には、問題の投稿コードからはっきりしていない

0

テストする環境はありませんが、オブジェクトがスライスされていると思われます。

は、これらのいずれかを試してみてください。

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

これはもっと安全ですが、ここでは2つのタイプが互いに継承することが知られているのでここでは不必要です。スライスする必要はありません。 –

0

で十分です。私は以下のことを行うだろう第2のケースで

:STDを含むラムダに設定なってしまったのUserAgentでdataReadのstd ::関数がありました

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