C++ Interface from C API

  api-design, c++, iterator, range-based-loop

I’m trying to provide a C++ Interface from an existing C-API. The C-API is pretty small and the header file includes two opaque structs as well as some simple functions.

The header looks similiar to this:

typedef struct C_Element C_Element;

// multiple getter to retrieve the members data

typedef struct C_List C_List;

C_List *create();
void *free(C_List *list);
C_Element *next(C_List *list);
// get element by random access
C_Element *get(C_List *list, int pos);
int size(C_List list*);

So it is possible to retrieve each element by consecutively calling next()

For the C++ Interface i wanted to supply an Iterator, so it is possible to use a range-based for loop to retrieve the elements, but I’m struggling with the implementation. My C++ header currently looks like this:

class Element {
  public:
    Element(C_Element *ptr) : ptr_{ptr}

    //getter
  private:
    C_Element *ptr_;
}

class List {
  using ListPtr = std::unique_ptr<C_List, decltype(&free)>;

  class Iterator {
    using difference_type = std::ptrdiff_t;
    using value_type = Element;
    using pointer = value_type *;
    using reference = value_type &;
    using iterator_category = std::input_iterator_tag;

    public:
      Iterator(Element *ptr) : ptr_{ptr}{}

      reference operator*() const {
        return *ptr_;
      }
      
      pointer operator->() {
        return ptr_;
      }
 
      Iterator &operator++() {
        ptr_++;
        return *this;
      }

      friend bool operator==(const Iterator &a, const Iterator &b) {
        return a.ptr_ == b.ptr_;
      }

      friend bool operator!=(const Iterator &a, const Iterator &b) {
        return a.ptr_ != b.ptr_;
      }

    private:
      Element *ptr_;
  };

  public:
    List() : list_{create(), free}{}

    Iterator begin() {
      // retrieve first element
      Element e = const_cast<C_Element *>(next(list_));
      return Iterator(&e)
    }

    Iterator end() {
      auto size = size(list_.get());
      Element e = const_cast<C_Element *>(get(list_.get(), size);
      return Iterator(&e);
    }
  public:
    ListPtr list_;
};

Test-Implementation:

int main(int argc, char *argv[]) {
  List list();

  for (auto &entry : list) {
    std::cout << entry.getName() << std::endl;
  }
}

Seems to either throw a ‘segmentation fault’ or ‘basic_string:: M_construct null not valid’ when executing, compilation works fine.

Does anyone have an idea how I can fix this?

Source: Windows Questions C++

LEAVE A COMMENT