我在遗留应用中使用shared_ptr等实现了一个新模块,但是当shared_ptr调用析构函数时,我遇到了访问冲突。
应用程式:
case ENUM_DATA:
{
std::tr1::shared_ptr<CDataMsg> msg(new CDataMsg(_stringmsg)); // _stringmsg is initialized before
Process(msg);
break;
}
过程():
bool Process(std::tr1::shared_ptr<CDataMsg> msg)
{
try
{
switch (msg->getDataType())
{
case ENUM_MYDATATYPE:
{
std::tr1::shared_ptr<CMyData> base(msg->getData());
std::tr1::shared_ptr<CMyDataChild> data(std::tr1::static_pointer_cast<CMyDataChild>(base));
// do some stuff with data
std::tr1::shared_ptr<CRequest> request(new CRequest(data->getParam1(), data->getParam2()));
handler->AddRequest(request->getBin());
break;
}
default:;
}
return true;
}
catch (...)
{
// exception handling
}
return false;
}
析构函数:
CDataMsg::~CDataMsg()
{
if (m_data)
delete m_data;
m_data = NULL;
}
m_data是CMyData *(此时无法更改)。
CDataMsg是一个容器,它包含CMyData类型的数据。 CmyDataChild是CMyData的子类,在这里使用。
我在析构函数中有断点,但调试器仅在shared_ptr调用它时停止,然后我已经获得了访问冲突。
答案 0 :(得分:2)
每当我看到这样的错误时,我立即想到双重删除。
std::tr1::shared_ptr<CMyData> base(msg->getData());
if (m_data) delete m_data; //- in CDataMsg destructor
'm_data'有可能被删除两次吗?一旦进入shared_ptr,一次进入CDataMsg析构函数。
答案 1 :(得分:1)
正如您在评论中确认的那样msg->getData()
会返回指向msg
成员变量的指针(可能是m_data
),当switch
块范围时,它将被删除退出:
case ENUM_MYDATATYPE:
{
std::tr1::shared_ptr<CMyData> base(msg->getData());
std::tr1::shared_ptr<CMyDataChild>
data(std::tr1::static_pointer_cast<CMyDataChild>(base));
// do some stuff with data
std::tr1::shared_ptr<CRequest>
request(new CRequest(data->getParam1(), data->getParam2()));
handler->AddRequest(request->getBin());
break;
}
稍后当msg
块范围退出时,将调用switch
的析构函数:
case ENUM_DATA:
{
std::tr1::shared_ptr<CDataMsg> msg(new CDataMsg(_stringmsg));
Process(msg);
break;
}
并尝试重新delete
成员变量m_data
。
此外:
case ENUM_MYDATATYPE:
{
std::tr1::shared_ptr<CMyData> base(msg->getData());
std::tr1::shared_ptr<CMyDataChild>
data(std::tr1::static_pointer_cast<CMyDataChild>(base));
...
}
data
指向与base
相同的对象。当此范围退出base
时,将deleted
两次。