为写入指针创建一个行为良好的迭代器 API
Create a well-behaved iterator for a write-to-pointer API
我必须为仅具有旧式 "write-out to pointer" 访问器的 API 创建一个迭代器。有问题的 API 是 OGR 的;有问题的 classes 之一是 OGRLineString
(供参考:http://www.gdal.org/classOGRLineString.html)。这个 class 存储了一些点,可以使用以下 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
hack 将无济于事。
是否有任何sane/clean方法来添加迭代器而不修改OGRLineString
的原始来源?例如,有没有办法向原始 class 添加功能或修改它,就像 Ruby 的 "monkey patching" 功能一样?或者观察容器的生命周期以清理迭代器返回的 OGRPoint
个实例?
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);}
此 "pseudo pointer" return 类型在您需要管理 returned 值的生命周期的代码时使用。它也可以用于 "return a mutable reference" 用于实际上不存在的内部成员。 vector<bool>
在内部使用位域而不是 bool
对象,但使用相同的模式 return 来自 operator[]
.
的可变引用
这假设 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()};
}
我必须为仅具有旧式 "write-out to pointer" 访问器的 API 创建一个迭代器。有问题的 API 是 OGR 的;有问题的 classes 之一是 OGRLineString
(供参考:http://www.gdal.org/classOGRLineString.html)。这个 class 存储了一些点,可以使用以下 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
hack 将无济于事。
是否有任何sane/clean方法来添加迭代器而不修改OGRLineString
的原始来源?例如,有没有办法向原始 class 添加功能或修改它,就像 Ruby 的 "monkey patching" 功能一样?或者观察容器的生命周期以清理迭代器返回的 OGRPoint
个实例?
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);}
此 "pseudo pointer" return 类型在您需要管理 returned 值的生命周期的代码时使用。它也可以用于 "return a mutable reference" 用于实际上不存在的内部成员。 vector<bool>
在内部使用位域而不是 bool
对象,但使用相同的模式 return 来自 operator[]
.
这假设 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()};
}