Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize an iterator to something invalid if the container is not known?

I want to use a visitor given to a more complex function which should inflict changes on a container via the visitor of which is has only general knowledge. The example is reduced to a minimum. The real visitor has more functions and does not necessarily handle a container at all.

class IntersectionHandler{
public:  
  virtual void advance()=0;
  virtual void treatIntersection()=0;
};

class OverlapDisabler: public IntersectionHandler{
private:
  std::vector<Segment>  mEmpty;
  std::vector<Segment>* mpLinesToSearch;
  std::vector<Segment>::iterator mLineIter;

public:
  InsideCollector():mEmpty(),mpLinesToSearch(&mEmpty),mLineIter(mEmpty.end(){}

  void setLineContainer(std::vector<Segment>* lines){
    mpLinesToSearch = lines;
    mLineIter = mpLinesToSearch->begin();                                                            
  }

  void advance(){
    if(mLineIter != mpLinesToSearch->end()) ++mLineIter;
  }
  void treatIntersection(){
    if(mLineIter != mpLinesToSearch->end()) mLineIter->disable();
  }    
};

To intitailize the iterator I use a dummy vector, that I must keep as a class member in this case. Usually I would initialise the iterator with some globally invalid value such as 0 for a pointer.

Unfortunately 0 is not a valid value for an iterator with many compilers and also seems a little odd to use. Is there a cleaner way to accomplish what I am trying without resorting to an empty dummy container?

like image 524
Martin Avatar asked Feb 12 '23 20:02

Martin


2 Answers

The answer

You can't, there is no value for standard iterators that puts them into an "invalid state".


Proposed solution

Instead of relying on the value of mLineIter, default-initialize mLineIter and initialize mpLinesToSearch to nullptr in the constructor.

This way you will now that mLineIter isn't a valid iterator if mpLinesToSearch is still nullptr.


SAMPLE IMPLEMENTATION

class OverlapDisabler: public IntersectionHandler{
private:
  std::vector<Segment>* mpLinesToSearch;
  std::vector<Segment>::iterator mLineIter;

public:
  InsideCollector() : mpLinesToSearch (nullptr), mLineIter() { }

  ...

  void advance(){
    if (mpLinesToSearch == nullptr)
      return; // no iterator to increment

    if(mLineIter != mpLinesToSearch->end()) ++mLineIter;
  }

 ...     

  void treatIntersection(){
    if(mpLinesToSearch == nullptr)
      return; // the iterator doesn't refer to any element

    if(mLineIter != mpLinesToSearch->end()) mLineIter->disable();
  }    
};

( Note: If you are compiling your source as C++03, nullptr isn't available; if that is the case use NULL or 0 to initialize your pointer )

like image 58
Filip Roséen - refp Avatar answered Feb 15 '23 09:02

Filip Roséen - refp


if boost is an option, you may use boost::optional

or since C++17, std::optional

like image 27
Jarod42 Avatar answered Feb 15 '23 09:02

Jarod42