2015-01-15 10 views
0

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

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

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

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

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

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

+0

Вы должны смотреть на то, как 'вектор :: оператор []' работы, которая покажет вам, как решить эту причуду. –

+0

Что вы делаете сейчас, что приводит к утечке памяти? Почему итератор не управляет «OGRPoint»? Что делает ваш итератор? –

+0

Может использоваться OGRPoint со значением-семантикой? т.е. он имеет экземпляр-конструктор и т. д.? В этом случае сделайте это вместо «нового». если нет, используйте smartpointers – sp2danny

ответ

1

Предполагается, что 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()}; 
} 
+0

Большое спасибо! После довольно некоторой работы (и чтения на C++-связанных финетах), эта версия была лучше всего подходит для моих нужд. Обозначение «копирование-построение» и «общий указатель» и «необработанный указатель», наконец, помогли мне понять проблему, с которой я столкнулся. Еще раз спасибо! – Technaton

+1

Это выглядит как полный и полный итератор, но без 'operator->', этот итератор выполняет только концепцию 'output_iterator'. Также отсутствуют все typedef.Если добавить их, конструктор по умолчанию и 'operator + (int, iterator)', то он может получить полный 'random_access_iterator_tag'. http://stackoverflow.com/a/8054856/845092 –

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

+0

Концепция вывода указателя была для меня новой, спасибо большое! Я многому научился благодаря вашему ответу и sp2danny. Я только позже увидел, что я также зависит от класса Factory OGR (для чтения/записи WKT/WKB), поэтому указатель на выходе выглядел более навязчивым. Тем не менее, спасибо за предложение, которое расширило мои знания на С ++! – Technaton

 Смежные вопросы

  • Нет связанных вопросов^_^