deathNode
deathNode

Reputation: 134

runtime error using std map for comparison

Firstly, there is somewhat a similar question asked here: Unusual std::map runtime error.

but since there is no real solution there, I would like ask it again, because I am really stuck and clueless.

My code is as follows:

struct MyObj{
//constructor
MyObj(){}
std::map<std::string, std::string> m_fooMap;

bool operator==(const MyObj& other)
{
    if (m_fooMap.size() != other.m_fooMap.size())
        return false;

    std::map<std::string, std::string>::const_iterator i, j;
    i = m_fooMap.cbegin();
    j = other.m_fooMap.cbegin();
    for (; i != m_fooMap.cend(), j != other.m_fooMap.cend(); ++i, ++j)
    {
        if(i->first.empty() || j->first.empty())
            continue;

        if (i->first != j->first)
            return false;

        if (i->second != j->second)
            return false;
    }

  return true;
}

bool operator!=(const MyObj& other)
{
    return !operator==(other);
}
};

struct AnotherObj{
std::map<std::string, MyObj> m_collectionOfObjs; //always guaranteed to contain atleast one entry

bool operator==(const AnotherObj &other) const
    {
        for (auto& objIt : m_collectionOfObjs)
        {
            auto findSeriesIt = other.m_collectionOfObjs.find(objIt.first);

            if (findSeriesIt == other.m_collectionOfObjs.end())
                return false;

            //else found, see if the internal content is the same?
            else
            {
                if (objIt.second != findSeriesIt->second)
                    return false;
            }
        }

        //else
        return true;
    }
};

now, I have a std::vector anotherObjVec; And I need to compare the items inside this vector, with each other. for which I use the == operator.

Now at random instances everytime, even though the input data is the same, there seems to be a runtime error. The error points inside the "xtree" file, to the following code.

_Nodeptr _Lbound(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval
    _Nodeptr _Pnode = _Root(); //<------------ THIS line is where it points to
    _Nodeptr _Wherenode = this->_Myhead;    // end() if search fails

    while (!this->_Isnil(_Pnode))
        if (_DEBUG_LT_PRED(this->_Getcomp(), this->_Key(_Pnode), _Keyval))
            _Pnode = this->_Right(_Pnode);  // descend right subtree
        else
            {   // _Pnode not less than _Keyval, remember it
            _Wherenode = _Pnode;
            _Pnode = this->_Left(_Pnode);   // descend left subtree
            }

    return (_Wherenode);    // return best remembered candidate
    }

I am stuck and have no idea what to do next. I even tried initiating the constructor like this:

MyObj() : m_fooMap(std::map<std::string, std::string>()){}

Using C++11, Visual Studio 2012(v110)

Upvotes: 0

Views: 716

Answers (4)

deathNode
deathNode

Reputation: 134

Turns out the map was not instantiated correctly. This happened to me because I was using std::shared_ptr and storing it in a std::vector. Then iterating over it, one of shared ptrs was a nullptr. No idea why that happened, because it is a shared ptr and it being in the vector should still keep a reference count up, but I just changed the iteration technique over the vector and it works now.

Upvotes: 0

rafix07
rafix07

Reputation: 20969

Your words

even though the input data is the same, there seems to be a runtime error.

so it looks that operator== should return true at the end of block, but your function doesn't return any value (if your maps are empty your functions reaches the end of block where there is no return statement):

bool operator==(const MyObj& other)
{
    if (m_fooMap.size() != other.m_fooMap.size())
        return false;

    std::map<std::string, std::string>::const_iterator i, j;
    i = m_fooMap.cbegin();
    j = other.m_fooMap.cbegin();
    for (; i != m_fooMap.cend(), j != other.m_fooMap.cend(); ++i, ++j)
    {
        if(i->first.empty() || j->first.empty())
            continue;

        if (i->first != j->first)
            return false;

        if (i->second != j->second)
            return false;
    }
  // ??? return is missing here
}

so it is undefined behaviour

(from):

Flowing off the end of a value-returning function (except main) without a return statement is undefined behavior.

Upvotes: 1

kmdreko
kmdreko

Reputation: 60787

You're comparing iterators from different maps:

auto findSeriesIt = other.m_collectionOfObjs.find(objIt.first);
if (findSeriesIt == m_collectionOfObjs.end())
    return false;

findSeriesIt is from the other.m_collectionOfObjs map but you're comparing it to the end of m_collectionOfObjs. It should be:

auto findSeriesIt = other.m_collectionOfObjs.find(objIt.first);
if (findSeriesIt == other.m_collectionOfObjs.end())
    return false;

Upvotes: 1

user7860670
user7860670

Reputation: 37599

i != m_fooMap.cend(), j != other.m_fooMap.cend() uses comma operator, discarding first operand. It does not check both conditions so when i is equal to end iterator it may be later dereferenced. You should use and operator instead:

(m_fooMap.cend() != i) and (other.m_fooMap.cend() != j);

Upvotes: 0

Related Questions