Нарушение прав доступа при использовании shared_ptr в устаревшем коде - PullRequest
0 голосов
/ 27 января 2012

Я внедряю новый модуль с использованием shared_ptr и т. Д. В нашем устаревшем приложении, однако я получаю нарушение прав доступа, когда shared_ptr вызывает деструктор.

app:

case ENUM_DATA:
{
    std::tr1::shared_ptr<CDataMsg> msg(new CDataMsg(_stringmsg)); // _stringmsg is initialized before
    Process(msg);
    break;
}

Process ():

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 ]

2 голосов
/ 27 января 2012

Всякий раз, когда я вижу подобные ошибки, я сразу же думаю о двойном удалении.

std::tr1::shared_ptr<CMyData> base(msg->getData());
if (m_data) delete m_data;  //- in CDataMsg destructor

Возможно ли, что m_data удаляется дважды? Один раз в shared_ptr и один раз в деструкторе CDataMsg.

1 голос
/ 27 января 2012

Как вы подтвердили в своем комментарии, 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 редактироваться дважды.

...