Search code examples
c++vectorcursor

Run cursor through vector while checking its bounds


I have a cursor that has its "position" determined by another part of the code. My intention is to have this cursor check through the next and previous object of a vector and check for a condition. If it's valid, the cursor takes this object's position. Here's some sample code of my idea:

class A
{
bool valid;
public:
A(bool v)       {valid=b;}
bool IsValid()  {return valid;}
};

void CheckNearbyValidity()
{
    /*if the object to the right is valid, update position to this object*/
    if(exampleVector.at(cursor-1).IsValid())
    {
        /*do stuff*/
        cursor = (cursor-1);
    }
    /*if the object to the right isnt valid, try the same thing to the left*/
    else if(exampleVector.at(position+1).IsValid())
    {
        /*do stuff*/
        cursor = (cursor+1);
    }

    /*leave if none are valid*/
}

The problem I encounter here is that if the cursor is at the start or end of the vector, checking the if conditions will cause it to throw an out of range exception.

My solution was to check if the new cursor position was valid before querying the vector:

 void CheckNearbyValidity()
 {
     /*if the object to the right is valid, update position to this object*/
     if(cursor-1 >= 0)
     {
        if(exampleVector.at(cursor).IsValid())
        {
            /*do stuff*/
            cursor = (cursor-1);
        }
    }
    /*new position makes the next condition always true and returns cursor to the same position*/
    if(cursor-1 < exampleVector.size())
    {
        if(exampleVector.at(cursor+1).IsValid())
        {
        /*do stuff*/
        cursor = (cursor+1);
        }
    }
    /*leave if none are valid*/
}   

The new problem was that since I could no longe use "else", both conditions would be valid and the cursor would remain where it started.

My workaround to this problem was to surround the function in a while loop, and break when necessary:

void CheckNearbyValidity()
{
    while(true)
    {
        if(cursor-1 >= 0)
        {
            if(exampleVector.at(cursor-1).IsValid())
            {
                /*do stuff*/
                position = (cursor-1);
                break;
            }
        }
        if(cursor-1 >= 0)
        {
            if(exampleVector.at(cursor+1).IsValid())
            {
                /*do stuff*/
                position = (cursor+1);
                break;
            }
        }
        break;
    }
}

My question is, is the "single" while loop approach a bad idea? Is there a better way to manipulate this cursor?


Solution

  • You should harness the power of &&:

        if (cursor-1 >= 0 && 
            exampleVector.at(cursor-1).IsValid())
        {
            /*do stuff*/
            position = (cursor-1);
        }
        else if (cursor+1 < exampleVector.size() && 
                 exampleVector.at(cursor+1).IsValid())
        {
            /*do stuff*/
            position = (cursor+1);
        }
    

    This allows you to connect the two statements together as an if-else as you had originally, only with the additional validation step checking cursor against the vector bounds.

    The && performs short-circuit evaluation. If cursor-1 >= 0 evaluates to false, then the code skips evaluating exampleVector.at(cursor-1).IsValid() and jumps immediately to evaluating the else clause.

    Likewise, in the else if clause, if cursor+1 < exampleVector.size() evaluates to false, the && short-circuits and the code skips evaluating exampleVector.at(cursor+1).IsValid(), again making it safe.