在遗留代码上使用shared_ptr时的访问冲突

时间:2012-01-27 12:03:49

标签: visual-c++ shared-ptr access-violation

我在遗留应用中使用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调用它时停止,然后我已经获得了访问冲突。

2 个答案:

答案 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两次。