C++ shared_ptr inheritance memory leak
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();
}
精彩评论