为写入指针 API 创建行为良好的迭代器



我必须为仅具有旧式"写出到指针"访问器的 API 创建一个迭代器。有问题的 API 是 OGR 的;其中一个有问题的类是OGRLineString(供参考:链接)。此类存储许多点,可以使用以下 getter 方法访问这些点:

 void OGRLineString::getPoint(int pos, OGRPoint *out)

为了使用访问器,创建一个新的OGRPoint对象,并将指向它的指针传递给方法,该方法将数据写入分配的对象。例如:

OGRPoint *p = new OGRPoint();
lineString->getPoint(0, p);

现在,我想实现一个(类似STL)迭代器。即使我在各处放置大警告标志,说明提供的OGRPoint是不可修改的(即 const ),并且如果另一段代码修改正在迭代的OGRLineString,也不会更新,我遇到了内存泄漏问题OGRPoint const &operator*() const,因为 API 要求我传递自定义分配的OGRPoint实例, 但是迭代器必须分配一个。此外,当迭代器本身被删除时,不应删除迭代器返回的OGRPoint。此外,该OGRLineString不存储为getPoint复制的OGRPoint的实际实例,而是存储 x/y/z 坐标的简单结构;所有必需的附加信息(例如,空间参考)都将复制到访问器中。因此,一个简单的#define private public黑客无济于事。

有没有任何理智/干净的方法可以在不修改原始OGRLineString的情况下添加迭代器? 例如,有没有办法像 Ruby 的"猴子修补"功能那样向原始类添加或修改它?或者观察容器的生存期,以便清理迭代器返回的OGRPoint实例?

这假设 OGRPoint 是可复制构造的。如果没有,请使用智能指针。

#include <iterator>
#include <ogr_geometry.h>
struct OGR_SimpleCurve_Points_Iterator : std::iterator< std::random_access_iterator_tag, const OGRPoint >
{
    OGR_SimpleCurve_Points_Iterator( OGRSimpleCurve* curve=nullptr, int index=0 )
        : curve(curve), index(index) {}
    OGR_SimpleCurve_Points_Iterator& operator++() { ++index; return *this; }
    OGR_SimpleCurve_Points_Iterator operator++(int) { OGR_SimpleCurve_Points_Iterator ret(*this); ++index; return ret; }
    OGR_SimpleCurve_Points_Iterator& operator--() { --index; return *this; }
    OGR_SimpleCurve_Points_Iterator operator--(int) { OGR_SimpleCurve_Points_Iterator ret(*this); --index; return ret; }
    OGR_SimpleCurve_Points_Iterator& operator+=(int n) { index+=n; return *this; }
    OGR_SimpleCurve_Points_Iterator& operator-=(int n) { index-=n; return *this; }
    OGR_SimpleCurve_Points_Iterator operator+(int n) { return OGR_SimpleCurve_Points_Iterator{curve,index+n}; }
    OGR_SimpleCurve_Points_Iterator operator-(int n) { return OGR_SimpleCurve_Points_Iterator{curve,index-n}; }
    int operator-(const OGR_SimpleCurve_Points_Iterator& other) { return index-other.index; }
    OGRPoint operator*() { OGRPoint p; curve->getPoint(index,&p); return p; }
    OGRPoint operator[](int ofs) { OGRPoint p; curve->getPoint(index+ofs,&p); return p; }
    bool operator == ( const OGR_SimpleCurve_Points_Iterator& other ) { return index==other.index; }
    bool operator != ( const OGR_SimpleCurve_Points_Iterator& other ) { return index!=other.index; }
    bool operator  > ( const OGR_SimpleCurve_Points_Iterator& other ) { return index >other.index; }
    bool operator >= ( const OGR_SimpleCurve_Points_Iterator& other ) { return index>=other.index; }
    bool operator  < ( const OGR_SimpleCurve_Points_Iterator& other ) { return index <other.index; }
    bool operator <= ( const OGR_SimpleCurve_Points_Iterator& other ) { return index<=other.index; }
private:
    OGRSimpleCurve* curve;
    int index;
};
OGR_SimpleCurve_Points_Iterator begin( OGRSimpleCurve* curve )
{
    return OGR_SimpleCurve_Points_Iterator{curve};
}
OGR_SimpleCurve_Points_Iterator end( OGRSimpleCurve* curve )
{
    return OGR_SimpleCurve_Points_Iterator{curve,curve->getNumPoints()};
}
class this_is_my_iterator;
class OutputOGRPoint {
    explicit OutputOGRPoint(this_is_my_iterator* parent_)
        :parent(parent_), p(new OGRPoint()) 
    {}
    ~OutputOGRPoint();
    operator OGRPoint *() {return p;}
    OutputOGRPoint(OutputOGRPoint &&)=default;
    OutputOGRPoint&operator=(OutputOGRPoint &&)=default;
private:    
    this_is_my_iterator* parent;
    std::unique_ptr<OGRPoint> p;
};
class this_is_my_iterator {
    OutputOGRPoint operator*()(return OutputOGRPoint(this);}
private:
    friend OutputOGRPoint;
    void apply_operator_star_changes(OGRPoint *p);
};
inline OutputOGRPoint::~OutputOGRPoint()
{parent->apply_operator_star_changes(p);}

当您需要管理返回值生存期的代码时,使用此"伪指针"返回类型。 它还可用于为实际上不存在的内部成员"返回可变引用"。 vector<bool>内部使用位域而不是bool对象,但使用相同的模式从operator[]返回可变引用。

最新更新