【发布时间】:2011-10-04 18:26:43
【问题描述】:
我有一个 shared_ptr 指向子类基础的情况。
当shared_ptr去删除指针时,只有父析构函数被调用。
父母析构函数是虚拟的,孩子不是,尽管我已经尝试过所有组合。
我在 valgrind 中有该程序,它显示在创建对象时在 new 语句中创建了内存。而且我知道父析构函数被调用,但子析构函数没有。
这是孩子:
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 的几个容器不同,当一个包含被销毁时,是否调用了内部元素的析构函数?
请让我知道我还能提供什么来解决问题。
【问题讨论】:
-
从问题中发布的代码中不清楚何时应该删除共享指针。我查看了您链接中的代码(顺便说一句,这是不受欢迎的),那里有太多内容需要处理。您能否详细说明您希望何时删除共享指针?你怎么确定孩子的析构函数没有被调用(它不会像父母那样记录任何东西)?
-
一个简单的例子只是为了展示
std::shared_ptr正确处理这种情况:ideone.com/TRXVu。我必须支持 Chad 的问题,即你有多确定没有调用正确的析构函数? -
请提供重现问题的可编译运行代码。很有可能在您省略的代码中的某处发生切片。
-
n.m 我会尝试,但问题很大。如果您查看链接,我相信您可以轻松下载 src 文件夹并制作它。 (如果你点击快照就可以了)谢谢
-
您的扩展问题听起来像您有一个悬空的参考。有人持有
shared_ptr的时间比预期的要长,因此该对象永远不会被删除。这很容易由循环引用引起...a持有b,它持有c,它持有a,因此即使没有外部引用a,它们也不会被删除。考虑在不需要实际所有权的地方使用weak_ptr。此外,您的 lambda 表达式可能会存储在路径中的某个位置,并且它们也会保存副本。
标签: c++ inheritance c++11 memory-leaks shared-ptr