开发者

C++ shared_ptr inheritance memory leak

开发者 https://www.devze.com 2023-03-20 15:05 出处:网络
I have a situation where I have a shared_ptr to base of a child class. When the shared_ptr goes to delete the pointer, only the parent destructor is being called.

I have a situation where I have a shared_ptr to base of a child class.

When the shared_ptr goes to delete the pointer, only the parent destructor is being called.

The parents destructor is virtual, the childs is not, although I have experimented in all combinations.

I have the program in valgrind, and it show that memory is created at the new statement when object created. And I know the parent destructor is being called, but the child's isn't.

this is the child:

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::st开发者_如何学编程ring &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;
};

the parent:

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

Usage:

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.

Thank You.

Also please note the code above is still a work in process.

EDIT: I was wrong the child destructor is being called,

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

EDIT: I have done more testing and I am afraid the problem is complex than I hoped. The destructors are being called when the items are being destroyed however, the issue is once the UserAgent enters the system it doesn't get destroyed. Something is stopping from being destroyed.

if it makes and difference the are several containers of shared_ptr to the useragent, when a contain is destroy are the destructors of the elements inside called?

Please let me know what else I can provide to fix the problem.


There was a dataRead std::function in UserAgent which ended up getting set to a lambda containing a std::shared_ptr to itself stopping it self form destructing. I added a close() method and set the std::function to it default value.

Now all is well and it delete fine

Thanks for all your help any way


I suspect your object is being sliced, though I don't have an environment to test.

Try one of these:

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


In void Server::reset() auto_ptr is enough.

In second case I would do the followings:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号