Использование итератора без контейнера - PullRequest
2 голосов
/ 02 июня 2010

Я смешиваю некоторые библиотеки C и C ++, и у меня есть только один доступный указатель для некоторой работы в функции обратного вызова. Все, что мне нужно сделать, это перебрать вектор. Вот упрощенный, непроверенный пример:


bool call_back(void* data){
  done=...
  if (!done) cout << *data++ << endl;
  return done;
}

Обратите внимание, что эта функция находится в блоке extern "C" в C ++. call_back будет вызываться до тех пор, пока не будет возвращено значение true. Я хочу, чтобы он отслеживал следующий элемент каждый раз, когда он вызывается. data - это указатель на что-то, что я могу передать из другого места в коде (итератор в приведенном выше примере, но может быть любым). Что-то из data, вероятно, будет использовано для вычисления done. Я вижу два очевидных варианта для data:

  1. У data указатель на мой вектор.
  2. Пусть data указывают на итератор моего вектора.

Я не могу использовать итератор без наличия метода .end (), верно? Я не могу использовать один вектор (если, возможно, я не начну удалять его данные). Я мог бы сделать структуру с вектором и итератором, но есть ли лучший способ? Что бы вы сделали?

Ответы [ 3 ]

3 голосов
/ 02 июня 2010

Почему бы не указать данные на структуру со всей необходимой информацией.

Суть старых обратных вызовов в стиле "С" заключается в том, что пустота * может указывать на любой объект. Ваша функция обратного вызова знает, что это за тип, но это может быть что угодно.

typedef struct Plop
{
    std::vector<int>::iterator begin;
    std::vector<int>::iterator end;
} Plop;

bool call_back(void* data)
{
    // Or static_cast<> for the pedantic.
    // I like reinterpret_cast<> because it is a clue to humans that this is dangerious
    // and as long as the object was originally a Plop* pointer it is guaranteed to work.
    Plop*   info = reinterpret_cast<Plop*>(data);

    bool    done= info.begin == info.end;

    if (!done) cout << *data++ << endl;
    return done;
}
1 голос
/ 02 июня 2010

Я не могу использовать итератор без наличия метода .end (), верно?

Нет.Вы можете использовать итератор с результатом вызова функции .end ().Вам не нужно продолжать вызывать функцию .end () ... так что если вы просто сохраните оба итератора, то вы золотые.

Я не могу использовать вектор один (если толькоможет быть, я начну удалять его данные).

Не один, а с индексом std :: size_t, тогда это все, что вам нужно.и вектор и итератор, но есть ли лучший способ?Что бы вы сделали?

Если вам не нужно беспокоиться о поддержке других типов контейнеров, я бы использовал:

 template<typename T> struct CALLBACK_DATA
 {
      std::vector<T>* array;
      std::size_t index;
 };

Если вам может потребоваться поддержка нескольких контейнеровтипов, тогда я бы использовал:

 template<typename T> struct CALLBACK_DATA
 {
     typedef std::vector<T> container_type;
     typedef typename std::vector<T>::const_iterator const_iterator;
     const_iterator current;
     const_iterator end;
 };

Итак, да, я бы либо передал вектор и индекс, либо пару итераторов, и я бы создал структуру для хранения данных.Если вы хотите избежать создания структуры, вы можете использовать std::pair, однако я лично считаю, что проще создать пользовательскую структуру для хранения этой информации.

0 голосов
/ 02 июня 2010

Как насчет разыменования итератора и передачи его значения в call_back? Затем увеличить его после возврата функции?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...