Создать корректный итератор для API записи в указатель

Мне нужно создать итератор для API, который имеет только методы доступа «запись в указатель» старого стиля. Рассматриваемый API — это OGR; один из рассматриваемых классов OGRLineString (Для справки: http://www.gdal.org/classOGRLineString.html). Этот класс хранит несколько точек, к которым можно получить доступ с помощью следующего метода получения:

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

Для использования средства доступа создается новый OGRPoint объект и передает указатель на него в метод, который записывает данные в выделенный объект. Например:

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

Теперь я хотел бы реализовать (STL-подобный) итератор. Даже если я повсюду размещу большие предупреждающие знаки о том, что OGRPoints являются немодифицируемыми (т.е. const), и не будет обновляться, если другой фрагмент кода изменяет OGRLineString это повторяется, я получаю проблему утечки памяти с OGRPoint const &operator*() constпотому что API требует, чтобы я передал пользовательский OGRPoint экземпляр, но итератор должен будет выделить один. Плюс OGRPointВозвращенные итератором значения не должны удаляться при удалении самого итератора. Кроме того, OGRLineString не хранит фактические экземпляры OGRPoint которые копируются для getPoint, но простые структуры, хранящие координаты x / y / z; вся необходимая дополнительная информация (например, пространственная привязка) копируется в средство доступа. Таким образом, простой #define private public взломать не поможет.

Есть ли вменяемый / чистый способ добавить итератор без изменение исходного источника OGRLineString? Например, есть ли способ добавить функции в исходный класс или изменить его, как это сделала бы функция Ruby «monkey patching»? Или посмотрите время жизни контейнера, чтобы очистить OGRPoint экземпляры, возвращаемые итератором?

0

Решение

Это предполагает, что 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()};
}
1

Другие решения

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[],

1

По вопросам рекламы [email protected]