итератор разыменования вызывает ошибку «невозможно преобразовать», когда кажется, что этого не должно быть

При использовании VS 2008 целевой средой является Windows CE с процессором ARM, если это имеет значение. Я знаю, что компилятор, который мы используем, тоже устарел...

Основная проблема, с которой я сталкиваюсь, заключается в том, что я пытаюсь создать свой собственный итератор для обертки карты, которую я написал, и перегрузка оператора->() доставляет мне проблемы. Это часть кода, которая вызывает у меня проблемы:

const pair<wstring, PropertyMap*>* ObjectMapIterator::operator->() const
{
    return &*m_MapIter;
}

Я знаю, что обычно не имеет смысла возвращать константную переменную, но я не могу понять, как это сделать таким образом, чтобы остальная часть программы была корректной без этого.

Ошибка, которую я получаю, заключается в следующем:

ошибка C2440: «возврат»: невозможно преобразовать из «const std::pair‹_Ty1,_Ty2> *» в «const std::pair‹_Ty1,_Ty2> *»

Заголовок для этого итератора выглядит так:

class ObjectMapIterator
{
public:
    ObjectMapIterator(const ObjectMap& rObjectMap);
    const ObjectMapIterator& operator++(int rhs);
    std::pair<std::wstring, PropertyMap*> operator*() const;
    const std::pair<std::wstring, PropertyMap*>* operator->() const;
    bool isDone() const;

private:
    const std::map<std::wstring, PropertyMap*>* m_pPropertyMaps;
    std::map<std::wstring, PropertyMap*>::const_iterator m_MapIter;
};

Как видите, и m_MapIter, и возвращаемое значение перегруженного оператора одинаковы... Я взял все операторы const из файлов .h и .cpp для этой части проекта и перекомпилировал с той же ошибкой. , так что я не думаю, что это проблема с этим.

Если вместо этого я сделаю что-то подобное, программа скомпилируется:

const pair<wstring, PropertyMap*>* ObjectMapIterator::operator->() const
{
    const pair<wstring, PropertyMap*>* returnVal = new pair<wstring, PropertyMap*>(*m_MapIter);
    return returnVal;
}

Я знаю, что это приведет к утечке памяти, я не помещал его в умный указатель только для того, чтобы сэкономить место для публикации этого.

Вот весь файл .cpp на случай, если вы сочтете это важным:

#include "stdafx.h"
#include "ObjectMap.h"

using namespace std;

ObjectMapIterator::ObjectMapIterator(const ObjectMap& rObjectMap)
    :m_pPropertyMaps(&(rObjectMap.m_PropertyMaps)),
     m_MapIter(m_pPropertyMaps->begin())
{}

const ObjectMapIterator& ObjectMapIterator::operator++(int rhs)
{
    if(m_MapIter != m_pPropertyMaps->end())
    {
        m_MapIter++;
        return *this;
    }
    else
    {
        return *this;
    }
}

pair<wstring, PropertyMap*> ObjectMapIterator::operator*() const
{
    return *m_MapIter;
}

const pair<wstring, PropertyMap*>* ObjectMapIterator::operator->() const
{
    return &*m_MapIter;
}

bool ObjectMapIterator::isDone() const
{
    return m_MapIter == m_pPropertyMaps->end();
}

Определение ObjectMapIterator находится внутри файла ObjectMap.h. Поэтому я не забываю включить ObjectMapIterator.

Я слишком долго ломал голову над этим. Пожалуйста, дайте мне знать, если вы что-нибудь выясните. Спасибо!


person c.hughes    schedule 21.03.2012    source источник


Ответы (1)


std::map::const_iterator возвращает временное значение, а не ссылку, поэтому вы пытаетесь получить адрес этого временного объекта и вернуть его.

Почему бы просто не вернуть pair по значению?

std::pair<std::wstring, PropertyMap*>* ObjectMapIterator::operator->() const
{
    return *m_MapIter;
}

Собственно, если ваш оператор будет возвращать std::map::const_iterator::pointer, как это делает std::map::const_iterator::operator->(), то все будет ок:

std::map<std::wstring, PropertyMap*>::const_iterator::pointer operator->() const
{
return &*m_MapIter;
}

Кроме того, поскольку значение, возвращаемое std::map::const_iterator::operator->(), определяется реализацией, возможно, было бы лучше использовать

auto operator->() const -> decltype(m_MapIter.operator->())
{
return (m_MapIter.operator->());
}
person Lol4t0    schedule 21.03.2012
comment
Хорошая точка зрения! Теперь я понимаю, где я ошибся, но это не совсем решает мою проблему. Вы должны вернуть указатель, чтобы оператор-› работал правильно, потому что C++ возьмет оператор типа objMapIter-›second и превратит его в (objMapIter.operator-›())-›second. Но это определенно поможет мне найти правильное решение. Спасибо! - person c.hughes; 22.03.2012
comment
Спасибо за внимание к этому. Вы, вероятно, только что спасли меня от еще пары часов поиска информации. Итераторы иногда сбивают с толку О_о. - person c.hughes; 22.03.2012