我想使用一个赋予更复杂函数的访问者,该函数应该通过访问者对容器进行更改,而访问者对容器只有一般知识。这个例子降到最低限度。真正的访问者有更多的功能,根本不一定要处理容器。
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();
}
};
为了初始化迭代器,我使用了一个伪向量,在这种情况下,我必须将其保留为类成员。通常我会用一些全局无效的值初始化迭代器,比如指针的0。
不幸的是,对于许多编译器的迭代器来说,0不是一个有效值,而且使用起来也有点奇怪。有没有一种更干净的方法可以在不使用空的虚拟容器的情况下完成我正在尝试的任务?
答案
不能,标准迭代器没有任何值可以使它们进入"无效状态">。
建议的解决方案
默认情况下,在构造函数中初始化mLineIter
并将mpLinesToSearch
初始化为nullptr
,而不是依赖于mLineIter
的值。
这样,如果mpLinesToSearch
仍然是nullptr
,那么mLineIter
就不是有效的迭代器。
示例实现
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();
}
};
(注意:如果您将源代码编译为C++03,则nullptr
不可用;如果是这种情况,请使用NULL
或0
初始化指针(
如果boost是一个选项,您可以使用boost::optional
或者从C++17开始,std::optional
有些容器的迭代器的默认构造函数似乎处于无效状态。对于std::set、std::map及其multi等价物来说,这是正确的。
看看这个:onlinegdb示例